VB.NET Two different approaches to generic cross-threaded operations; which is better?
VB.NET 2010, .NET 4
Hello,
I recently read about using SynchronizationContext
objects to control the execution thread for some code. I have been using a generic subroutine to handle (possibly) cross-thread calls for things like updating UI controls that utilize Invoke
. I'm an amateur and have a hard time understanding the pros and cons of any particular approach. I am looking for some insight on which approach might be preferable and why.
Update: This question is motivated, in part, by statements such as the following from the MSDN page on Control.InvokeRequired
.
An even better solution is to use the
SynchronizationContext
returned bySynchronizationContext
rather than a control for cross-thread marshaling.
And also, general confusion as to why, as I look around, a majority of answers to questions regarding this type of problem on SO suggest the Invoke
approach without mentioning this method.
Method 1:
Public Sub InvokeControl(Of T As Control)(ByVal Control As T, ByVal Action As Action(Of T))
If Control.InvokeRequired Then
Control.Invoke(New Action(Of T, Action(Of T))(AddressOf InvokeControl), New Object() {Control, Action})
Else
Action(Control)
End If
End Sub
Method 2:
Public Sub UIAction(Of T As Control)(ByVal Control As T, ByVal Action As Action(Of Control))
SyncContext.Send(New Threading.SendOrPostCallback(Sub() Action(Control)), Nothing)
End Sub
Where SyncContext
is a Threading.SynchronizationContext
object defined in the constructor of my UI form (I store it in a module... Not sure if that's the best choice):
Public Sub New()
InitializeComponent()
SyncContext = WindowsFormsSynchronizationContext.Current
En开发者_运维技巧d Sub
Then, if I wanted to update a control (e.g., Label1
) on the UI form, I would do:
InvokeControl(Label1, Sub(x) x.Text = "hello")
or
UIAction(Label1, Sub(x) x.Text = "hello")
So, what do y'all think? Is one way preferred or does it depend on the context? If you have the time, verbosity would be appreciated!
Thanks in advance,
BrianWell, I've been doing some reading and, since I'm not getting any responses, I figured I'd start a partial answer to my own question containing what I've found so far:
I found an interesting codeproject article discussing the use of SynchronizationContext
for marshaling code between threads (and specifically from worker threads to the UI thread). Some observations I found interesting:
- The UI thread's
SynchronizationContext
object is created upon creation of the first control in that thread. Before that, it is not defined. - The
SynchronizationContext
for the UI thread is not an instance of theSynchronizationContext
class, but of theSystem.Windows.Forms.WindowsFormsSynchronizationContext
class which is derived fromSynchronizationContext
. It is this class that defines the behavior ofPost
/Send
allowing marshaling of code from one thread to another. - An appeal of passing the UI thread's
SynchronizationContext
around rather than usingInvoke
is that you don't have to keep a reference to your UI form in logic in order to invoke it. - The
Post
method seems appealing for accomplishing things like indicator updates since it's non-blocking, but, as the article points out, exceptions thrown in posted code are thrown in the UI thread. i.e., a bug in code posted to the UI can crash the UI.Send
doesn't have this problem. Exceptions thrown when sending are thrown in the work thread.
Update: Here is another insightful article. In this article, Kael Rowan discusses a context in which using SynchronizationContext
might be preferable to a control instance's Invoke
/BeginInvoke
methods. He argues that, when writing a reusable library, it is not desirable to have to maintain a reference to a control outside of the library simply for invokation purposes. He provides code for a delegate that ensures any new thread created will share the UI thread's SynchronizationContext
.
Alright, well, it looks like I'm not going to get any more comments here. What I've written here is about as close as my ignorance allows me to get to an answer. If anyone has anything else to add, I'd surely appreciate it, but I'm moving on for now. :/
精彩评论