WPF Thread Affinity
Almost every WPF element has thread affinity. This means that access to such an element should be made only from the thread that created the element. In order to do so, every element that requires thread affinity is derived, eventually, from DispatcherObject class. This class provides a property named
Dispatcher
that returns theDispatcher
object associated with the WPF element.The Dispatcher Class
The
Dispatcher
class is used to perform work on his attached thread. It has a queue of work items and it is in charge of executing the work items on the dispatcher thread.
So, when you want to change a property of a WPF element from a thread different from the one who created the element, you should use the element’s
Dispatcher
property to dispatch the operation to the correct thread. This is done using the BeginInvoke method that accepts a method to be invoked.Where is the Dispatcher of the Thread Saved?
Every thread should have their dispatcher object, so you would think they will save the dispatcher on the Thread Local Storage (TLS).
It turns out they store a static list of all available dispatcher objects.
Of course, this list is synchronized using a
Of course, this list is synchronized using a
private global static
object (this is a common best practice when locking object).
Whenever the dispatcher of an object is needed, they go over the list, comparing the dispatcher’s
Thread
property with the current thread, until they find the correct dispatcher
object for this thread.
The reason, as they note in the comments is that managed TLS is rather expensive.
Above this list, they add the following optimization: before going over the dispatchers list, they check if the last given dispatcher is suitable, so only a thread context switch will derive a new list search.
Although strange, this usually isn't such a problem because most applications will only have one thread that creates UI elements, hence only one
Dispatcher
in the list.
The main method here is tagged with “STAThread” attribute. STA stands for “Single Threaded Apartment” model of programming. What STA states(or enforces) is that only one thread at a time will be executing our code and it will always be the same thread. All our Winform based application runs on STA model. Indeed one thread controlling the complete application looks like a big constraint and WPF people actually decided to move away from this model by opting an all together different approach. But the plan was abandoned because of various compatibility issues with other already existing applications. So our WPF applications too run on STA model. The thread the controls the application is commonly known as UIThread. “Dispatcher” concept is a mechanism introduced in WPF , with the help of which developer can have more explicit control on this UI thread as of what executes when. We will look into this in more details in the remaining section of this article. But before we take a deep dive, just try to keep in mind the below mentioned points about STA model.
- Thread that creates a given WPF application also own it and its not possible for any other thread to interact with these elements.
- In practice entire WPF application runs of single thread and its this thread that owns all the elements in the application.
Dispatcher Concept
As the name implies, the dispatching system is responsible for listening to various kinds of messages and making sure that any object that needs to be notified of that message is notified on the UI thread.
The classes responsible for “Dispatcher” concept are : DispatcherObject and Dispatcher. Actually its the “Dispatcher” class which provides the core implementation of dispatching mechanism. But its the “DispatcherObject” class which exposes a public property called “Dispatcher” , through which we can access the current instance of “Dispatcher” class. Have a look at the following class hierarchy diagram :
“DispatcherObject” class offers a public accessor property called “Dispatcher” using which we can access the current instance of “Dispatcher” class. Speaking about “Dispatcher” class, it is responsible for managing the work that takes place in our WPF application.Its this class which owns the application thread and internally it maintains a queue of work items. As the WPF application runs , Dispatcher class accepts incoming requests and executes them one at a time. In short dispatcher is an object which receives messages and delivers it to the correct object for further processing. Dispatcher class is pretty dense with lots of properties and methods. Going into the depth of Dispatcher class is beyond the scope of this article. One final thing on dispatcher class is that a given application can have only one instance of dispatcher class( as the application runs on single thread) , so Dispatcher class implements the very famous “Singleton” pattern. Because of that its impossible to create an instance of Dispatcher class in our custom code. Only with the help of public property “Dispatcher” offered by “DispatcherObject” that we can invoke members defined inside the “Dispatcher” class. Dispatcher class is instantiated as soon as any class which derives from “DispatcherObject” is accessed. All further request are processed by this newly created instance.
Coming back to “DispatcherObject” class , it offers two methods namely CheckAccess and VerifyAccess.
- CheckAccess : Determines whether the calling thread has access to this DispatcherObject. Only possible return values are true and false.
- VerifyAccess : VerifyAccess is more stringent compared to CheckAccess. It checks whether the calling thread is the one which created the DispatcherObject. If not it throws “InvalidOperationAccess” exception. Getting back to the example which I gave in the beginning, in that we were trying to update the UI through code which was running on a different thread. Internally VerifyAcess is invoked and once it verifies that calling code is different from the one which controls the application, it throws the “InvalidOperationError” exception.
Figure 1 DispatchPriority Prioritization Levels (in Priority Order)
Priority | Description |
---|---|
Inactive | Work items are queued but not processed. |
SystemIdle | Work items are only dispatched to the UI thread when the system is idle. This is the lowest priority of items that are actually processed. |
ApplicationIdle | Work items are only dispatched to the UI thread when the application itself is idle. |
ContextIdle | Work items are only dispatched to the UI thread after higher-priority work items are processed. |
Background | Work items are dispatched after all layout, rendering, and input items are processed. |
Input | Work items are dispatched to the UI thread at the same priority as user input. |
Loaded | Work items are dispatched to the UI thread after all layout and rendering are complete. |
Render | Work items are dispatched to the UI thread at the same priority as the rendering engine. |
DataBind | Work items are dispatched to the UI thread at the same priority as data binding. |
Normal | Work items are dispatched to the UI thread with normal priority. This is the priority at which most application work items should be dispatched. |
Send | Work items are dispatched to the UI thread with the highest priority. |
Ques : What is the difference between this.Dispatcher and element.dispatcher.
Ans: both will give same object because Dispatcher is base class and it implements singleton pattern.
No comments:
Post a Comment