This is an old topic. Let's make a small summary of this article.
For example, if you want to modify the title attribute of a form and a single thread, you can directly write the code. For example, you can modify the title in the window loaded event:
Private void window_loaded_1 (Object sender, routedeventargs E)
{
Title = "mgen ";
}
If you modify the statement using multiple threads:
System. Threading. threadpool. queueuserworkitem (_ => Title = "mgen ");
The result must be a program crash, throwing invalidoperationexception: The Calling thread cannot access this object because a different thread owns it. This is because the data of the UI thread cannot be directly accessed or modified by other threads.
Use Task directly:
Task. Factory. startnew () => Title = "mgen ");
It is also an illegal operation in nature, but the above Code will not cause a program crash, and the title attribute will not be modified. The reason is that the exception of the task will not be thrown immediately. At this time, the exception of the task is not noticed, this imperceptible exception will be thrown in the terminator execution thread during garbage collection (for more information, see this article :. net (C #) TPL: the task is not aware of exceptions and taskscheduler. unobservedtaskexception event)
One solution is to use the dispatcher thread model of WPF for modification. begininvoke will return immediately, and invoke will return after execution.
This. Dispatcher. begininvoke (new action () => Title = "mgen "));
Another method is to use synchronizationcontext. Its Post and send methods are similar to begininvoke and invoke, but synchronizationcontext abstracts the thread model of the UI platform, which is in the system. threading namespace can be used in Windows Forms and WPF.
However, note that the current attribute of synchronizationcontext is not null only in the UI thread. Therefore, you must use the synchronizationcontext. setsynchronizationcontext method to set the synchronizationcontext. Current attribute in the multi-threaded environment. The above code can be written as follows using synchronizationcontext:
// Use the synchronizationcontext. setsynchronizationcontext method to set the synchronizationcontext. Current attribute in a multi-threaded Environment
System. Threading. synchronizationcontext. setsynchronizationcontext (
New system. Windows. Threading. dispatchersynchronizationcontext (App. Current. Dispatcher ));
System. Threading. synchronizationcontext. Current. Send (_ => Title = "mgen", null );
In fact, the above Code is equivalent to calling the dispatcher. begininvoke method in WPF. Of course, synchronizationcontext is executed differently in different UI frameworks.
The task execution in TPL also supports synchronizationcontext by using taskschedation. fromcurrentsynchronizationcontext obtains a taskscheduler related to the current synchronizationcontext. With this taskschedcontext, the task is executed through the current synchronizationcontext, so that the task can safely access the data of the UI thread by calling the dispatcher method.
Code:
Task. Factory. startnew () => Title = "mgen", cancellationtoken. None, taskcreationoptions. None, taskscheduler. fromcurrentsynchronizationcontext ());
Finally, in the new C #5.0 and. in net 4.5 (or beta), you can use async/await to better simplify the asynchronous conversion, and the code after await will be automatically executed based on the current synchronizationcontext. For example, after performing some operations in another thread, modify the title attribute of the main thread.
Sample Code:
// Add async TO THE METHOD
Private async void window_loaded_1 (Object sender, routedeventargs E)
{
// 500 milliseconds of sleep in another thread for Simulation
Await task. Run () => system. Threading. thread. Sleep (500 ));
// Modify the data of the main UI thread after finishing the work
Title = "mgen ";
}