Tech Off Thread

14 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

I was told today to not worry cross-thread execution when...

Back to Forum: Tech Off
  • User profile image
    Verdant

    ....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
     

  • User profile image
    gadget

    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

  • User profile image
    Sven Groot

    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!

  • User profile image
    dcuccia

    gadget said:
    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

    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?

  • User profile image
    wkempf

    dcuccia said:
    gadget said:
    *snip*
    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.

  • User profile image
    Minh

    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?

  • User profile image
    wkempf

    Minh said:
    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.

  • User profile image
    Minh

    wkempf said:
    Minh said:
    *snip*
    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.
    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.

  • User profile image
    wkempf

    Minh said:
    wkempf said:
    *snip*
    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.

  • User profile image
    Minh

    wkempf said:
    Minh said:
    *snip*
    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.
    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.

  • User profile image
    wkempf

    Minh said:
    wkempf said:
    *snip*
    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.

  • User profile image
    Minh

    wkempf said:
    Minh said:
    *snip*
    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.
    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.

  • User profile image
    Sven Groot

    Minh said:
    wkempf said:
    *snip*
    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.

    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.

  • User profile image
    Minh

    Sven Groot said:
    Minh said:
    *snip*

    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.

    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

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.