How does synchronizationcontext work
BeginInvoke methods to implement the Send and Post methods. Or it can be DispatcherSynchronizationContext, it uses Dispatcher. Invoke and BeginInvoke. In a Winforms or WPF app, that provider is automatically installed as soon as you create a window. When you run code on another thread, like the thread-pool thread used in the snippet, then you have to be careful that you don't directly use objects that are thread-unsafe.
Like any user interface object, you must update the TextBox. Text property from the thread that created the TextBox. The Post method ensures that the delegate target runs on that thread. Beware that this snippet is a bit dangerous, it will only work correctly when you call it from the UI thread. Current has different values in different threads. Only the UI thread has a usable value.
And is the reason the code had to copy it. A more readable and safer way to do it, in a Winforms app:. Which has the advantage that it works when called from any thread. The advantage of using SynchronizationContext.
Current is that it still works whether the code is used in Winforms or WPF, it matters in a library. This is certainly not a good example of such code, you always know what kind of TextBox you have here so you always know whether to use Control. BeginInvoke or Dispatcher. Actually using SynchronizationContext. Current is not that common. The book is trying to teach you about threading, so using this flawed example is okayish. In real life, in the few cases where you might consider using SynchronizationContext.
FromCurrentSynchronizationContext to do it for you. But do note that they still misbehave the way the snippet does when you use them on the wrong thread, for the exact same reason. A very common question around here, the extra level of abstraction is useful but makes it harder to figure out why they don't work correctly. Hopefully the book also tells you when not to use it :. The purpose of the synchronization context here is to make sure that myTextbox. Windows requires that GUI controls be accessed only by the thread they were created with.
If you try assign the text in a background thread without first synchronizing through any of several means, such as this or the Invoke pattern then an exception will be thrown. What this does is save the synchronization context prior to creating the background thread, then the background thread uses the context. Post method execute the GUI code.
Yes, the code you've shown is basically useless. Why create a background thread, only to immediately need to go back to the main UI thread?
It's just an example. To the Source. Every thread has a context associated with it -- this is also known as the "current" context -- and these contexts can be shared across threads. The ExecutionContext contains relevant metadata of the current environment or context in which the program is in execution.
The SynchronizationContext represents an abstraction -- it denotes the location where your application's code is executed. A SynchronizationContext enables you to queue a task onto another context. Note that every thread can have its own SynchronizatonContext. For example: Suppose you have two threads, Thread1 and Thread2.
Say, Thread1 is doing some work, and then Thread1 wishes to execute code on Thread2. One possible way to do it is to ask Thread2 for its SynchronizationContext object, give it to Thread1, and then Thread1 can call SynchronizationContext.
Send to execute the code on Thread2. SynchronizationContext provides us a way to update a UI from a different thread synchronously via the Send method or asynchronously via the Post method. Current will return the UI thread's sync context.
How do I know this? If you create a WPF app and run my example, you'll see that when you click the button, it sleeps for roughly 1 second, then it will show the file's content. Even though Work1 method is passed to a thread, notice that it also accepts an object which is the SyncContext. If you look at it, you'll see that the UpdateTextBox method is executed through the syncContext. Post method and not the Work1 method. Take a look at the following:.
The last example and this one executes the same. Both doesn't block the UI while it does it jobs. In conclusion, think of SynchronizationContext as a thread. It's not a thread, it defines a thread Note that not all thread has a SyncContext.
If, for some reasons, you need to update the UI from a different thread, make sure that thread has the main UI thread's SyncContext and just call the Send or Post method on it with the method that you want to execute and you're all set. SynchronizationContext basically is a provider of callback delegates execution mainly responsible to assure that the delegates are run in a given execution context after a particular portion of code encapsulated in a Task obj of.
Net TPL of a program has completed its execution. From technical point of view, SC is a simple C class that is oriented to support and provide its function specifically for Task Parallel Library objects. Net application, except for console applications, has a particular implementation of this class based on the specific underlying framework, ie: WPF, WindowsForm, Asp Net, Silverlight, etc.
The importance of this object is bound to the syncronization between results returning from asyncronous execution of code and the execution of dependent code that is waiting for results from that asyncronous work.
And the word "context" stands for execution context, that is the current execution context where that waiting code will be executed, namely the syncronization between async code and its waiting code happens in a specific execution context, thus this object it is named SynchronizationContext: it represents the execution context that will look after syncronization of async code and waiting code execution.
This example is from Linqpad examples from Joseph Albahari but it really helps in understanding what Synchronization context does. Current object is of type DispatcherSynchronizationContext which is actually just a wrapper around the Dispatcher object and the Post and Send methods just delegate to Dispatcher.
BeginInvoke and Dispatcher. So even if you decide to use SynchronizationContext I think you end up calling dispatcher behind the scenes. Besides I think it is a bit cumbersome to use SynchronizationContext as you have to pass a reference to the current context to all threads that need to call into your UI. While the differences have been pointed out, I don't really see that reason for choosing one over another explicitly spelled out here.
So perhaps it would help to explain what problem the SynchronizationContext object is trying to solve in the first place:. So to answer your question of which one to choose, it would seem just from the criteria above that using the SynchronizationContext would be preferable to the Dispatcher. By using the SynchronizationContext to handle executing code on the UI thread, you can now easily separate your operations from the display via decoupled interface s. Which leads to the next point:.
If you have ever tried to mock an object as complex as the Dispatcher versus the SynchronizationContext , which has far fewer methods to deal with, you will quickly come to appreciate the far simpler interface offered by the SynchronizationContext.
NET, etc. If you write your code to interface to one set of APIs, your code becomes more portable and simpler to maintain as well as test. You don't need to even inject a context object Suppose we have a WPF application that has a single button. Upon clicking that button, you will start a long process of asynchronous work tasks interlaced with UI updates, and you need to coordinate IPC between the two. Notice this time through, we dont need to rely on external objects for synchronizing between threads.
This time it said thread 1 or whatever your current thread id said. You'll note that the await this time didn't cause the code to execute on a new thread.
What's this sorcery? Note that SynchronizationContext does not have a Start method on it. How the message loop a synchronization context uses is implemented is an opaque detail we're not supposed to consider. However, in our custom implementation, we need something to serve as our message loop, and I essentially just provided a boilerplate one behind that method to keep things simple. If you don't quite understand how it works yet, let me go over it again. Somewhere, there's a message loop.
Where it is in your code or the bowels of the framework is an implementation detail. The point is that whatever thread it runs, the message loop on is where the code will finally be executed. You call Send and Post from other threads with delegates "containing" your code to be "transported" and executed on that target thread. This allows for easy cross thread communication. Sometimes, like when you're in a console app or Windows service, you will not have a good SynchronizationContext to use.
The problem is there's no message loop. If you want one, you have to make one, and that's what this is for. It should be sufficient for custom threading scenarios where you need code executed on a thread of your choosing. We'll explore it here. First, we have a nested struct declaration and an important member field:. The message contains the " callback " I mentioned earlier, a field for optional user state which you passed to Send or Post and finally a ManualResetEventSlim which I'll explain as we get further along.
It is used for signalling to Send that we've processed the message so that Send is able to block until it's received. This type declares all the information we need to execute a delegate on the message loop thread. Next, we have something called a MessageQueue that holds Message struct instances as declared above. This class provides a thread safe way to communicate by posting and receiving Message s.
It does most of the heavy lifting, but we'll explore that as well eventually. The above is specific to our implementation of a SynchronizationContext. You may very well have your own way of communicating across threads, and you can implement whatever you like as long as it fulfills the necessary contract provided by SynchronizationContext.
Here are the Send and Post implementations for our custom synchronization context:. You can see Post is straightforward. Send is slightly more complicated because we must get notified when it finally completes, which is what our ManualResetEventSlim from earlier was before.
Here we create it, post it with the Message , and then wait on it. In our message loop, it gets Set signalling we can continue. Finally, we Dispose of the event. It might be more efficient to recycle these events but doing so is significantly more complicated and I'm not sure how much performance would be gained, if any. Note we can pass a State with the Message. It gets sent to the Callback for processing, and its value is arbitrarily defined by the consumer. Now let's look at our message loop in Start again, hopefully it will be a little clearer this time:.
Note how we're waiting for the message to complete. The reason this doesn't use Send , but does the same thing is I've been considering adding a check for a null Callback and throwing in Send if it finds one. This code ensures that the behavior here won't break if I add that check. The MessageQueue provides the core functionality to post and receive messages between threads.
0コメント