page 1 of 1
Comments: 13 | Views: 1129
....Using multiple threads, we were taught to just run the code outside vs and the debugger, which seems to work, but also seems completly wrong to me.

From a WinForms Form Object:

tKey = new Thread(ReadKeyboard);

public void ReadKeyboard()
{
    Text = "Keyboard acquired";
}

can someone verify that this is bad practice or otherwise?

i don't like skipping the debugger, so i used:
main.Invoke(new MethodInvoker(delegate() { Text = "Keyboard acquired"; }));

is this an acceptable "workaround"?

edit: main being a reference to the form object
 

I check inside the method to see if an invoke is required. If so have the delegate make a recursive call to the method, otherwise perform the action.

This is in vb but should be clear.

 Public Sub ReadKeyboard()
        If Me.InvokeRequired Then
            Dim x As Action = AddressOf ReadKeyboard
            Me.Invoke(x)
        Else
            me.Text = "Keyboard acquired"
        End If
 End Sub

Check out the invokerequired property of the control class.
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx

Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...
This is bad! You can't access the UI thread from any other thread, it's an inherent limitation of Win32. Doing what you're doing here might work some of the time, but it's not a good idea at all.

Always check InvokeRequired and use Invoke when needed!
This is a cross-cutting concern, no? I do this with the following extension methods:

public static void InvokeOnUIThread( this Control myControl, Action action );
public static void InvokeOnUIThread<T>( this Control myControl, Action<T> action, T parameter );

which would be used as follows:

this.InvokeOnUIThread( () => myControl.Text = "Keyboard acquired" );

Asked for feeback on this earlier...what do you guys think?
In your original post, I found it interesting you called this InvokeOnUIThread, but the implementation did a BeginInvoke.  Very different operational behaviors there.

This is mostly a matter of performance.  The normal pattern has slightly better performance, since we're only calling through a delegate when we absolutely must.  I'm not 100% sure about how things are implemented under the covers, but I'd suspect you'd be better off just calling Invoke (or BeginInvoke) without checking InvokeRequired, rather than wrapping this in a InvokeOnUIThread method.
Minh
Minh
WOOH! WOOH!
Yes, you should ALWAYS make sure that you're changing UI objects on the UI thread. And I believe you don't really have a choice in .Net 2.0. It would throw an exception otherwise.

But seeing the various syntax for doing so, I realize that C# utterly failed on making the intention of the act understandable.

Bleah
main.Invoke(new MethodInvoker(delegate() { Text = "Keyboard acquired"; }));

Bleah bleah
Public Sub ReadKeyboard()
        If Me.InvokeRequired Then
            Dim x As Action = AddressOf ReadKeyboard
            Me.Invoke(x)
        Else
            me.Text = "Keyboard acquired"
        End If
End Sub

Bleah bleah bleah
public static void InvokeOnUIThread( this Control myControl, Action action );
public static void InvokeOnUIThread<T>( this Control myControl, Action<T> action, T parameter );
this.InvokeOnUIThread( () => myControl.Text = "Keyboard acquired" );

How about just automatically synchronize UI access like Silverlight?

Because "automatic" serialization:

1.  May not be what a consumer intends.
2.  May actually lead to deadlock.

I believe that was the route WPF was originally taking, and they abandoned it.

Edit: Looked it up, and I'm wrong.  Avalon originally used an entirely different concept: the UIContext.  This wasn't much different from the way things work today (which is the way they work in practically all UI libraries), it was just much more abstracted with a "Monitor" type of interface.
Minh
Minh
WOOH! WOOH!
I think it's entirely based on performance. Perhaps the Win32 limitation impose a too heavy a performance penalty on automatic synch... but how is Silverlight able to do it?

Deadlock is only a possibility when you try to take out locks while already holding locks, right? It's too bad that even until now (for the exception of Silverlight), we still don't have a good solution for this problem.
The synchronization employed here is a "context switch via message queue".  Said message queue is one large lock.  I've seen code attempt to do automatic synchronization in this fashion, and it frequently results in deadlock.

I've got no clue how (or if) Silverlight does automatic synchronization.  As someone who knows a lot about multi-threading, though, I can tell you that automatic synchronization is terrible for performance and can often lead to hard to discover dead locks.  That statement is relevant beyond the UI synchronization we're talking about here.

Edit:  The first page I hit on Google suggests that Silverlight uses the exact same threading model that WPF does.  http://www.wintellect.com/CS/blogs/jprosise/archive/2008/03/26/threading-and-marshaling-in-silverlight-2-0.aspx

This is not automatic synchronization.
Minh
Minh
WOOH! WOOH!
I could've sworn I saw a post from ScottGu contradicting Jeff's post (which was in March).... Let me see if I can hunt it down.
Looking at the official Silverlight 2 documentation, no, the model is the same as WPF.  It's vastly simplified (Dispatcher doesn't have the concept of priority, for instance), but still the same model.  Actually, I find it interesting that Dispatcher doesn't have an Invoke method.  For that matter, DispatcherOperation doesn't have a Wait() method.  This means Silverlight provides "one way" context switches, and you have to roll your own solution for returning results.  I'd say WPF is several steps up from Silverlight, unlike your initial claim.
Minh
Minh
WOOH! WOOH!
Here's what I'm able to gather...

From this ScottGu post he had this code sample...



Later in the callback method, he assigned the data to the grid.

So either Scott is blatantly ignoring UI threading rules, or they work some sort of automatic UI thread synchronization, at least on callbacks.
Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...

I'm not sure if this is the case in Silverlight, but in regular .Net the Async pattern (unlike the Begin/EndInvoke pattern) makes sure that the Completed event is raised on the UI thread. So using UI methods from the DownloadStoriesCompleted event handler is safe since it's already on the correct thread.

This uses the AsyncOperation class introduced in .Net 2.0, it's also what BackgroundWorker uses internally.

Minh
Minh
WOOH! WOOH!
This uses the AsyncOperation class introduced in .Net 2.0, it's also what BackgroundWorker uses internally.

Oh, really? I did not know that.

That must be what's happening in Silverlight too then
page 1 of 1
Comments: 13 | Views: 1129
Microsoft Communities