同步 SynchronizationContext
来源:互联网 发布:php开发工具 编辑:程序博客网 时间:2024/05/21 09:48
Introduction
The SynchronizationContext
class is a new class belonging to the .NET Framework's System.Threading
namespace. The purpose of this class is to provide a model to make communication between threads easier and more robust. I will begin by describing how the SynchronizationContext
class helps us handle events using Windows Forms. I will also touch on a few of the other new classes in the System.ComponentModel
which use the SynchronizationContext
class that also help us with synchronization issues.
As a disclaimer, some of what I describe below is based on my experience, albeit brief, with these new classes rather than documentation. The documentation seems a bit sparse at this time. So while my understanding isn't complete, I'm hoping that what I share below will be helpful, and that I will be able to expand this article in the future as my understanding (and hopefully Microsoft's documentation) increases.
Background
在windows应用窗体应用程序中,对窗体上控件属性的任何修改都必须在主线程中完成。不能从其他线程
安全地访问控件的方法和属性。
Most of us are familiar with the prohibition against modifying a Control
from any thread other than the one in which it was created. Instead, an event generated on another thread must be marshaled to the Control
's thread using its (or the Form
that it belongs to) Invoke(调用)
or BeginInvoke
methods. These two methods belong to the ISynchronizeInvoke
interface, which the Control
class implements. Their purpose
is to take a delegate and invoke it on the same thread that the ISynchronizeInvoke
object is running. Typically, a Form
's method for responding to an event generated
on another thread looks like this:
private void HandleSomeEvent(object sender, EventArgs e)
{
if(InvokeRequired)
{
BeginInvoke(new EventHandler(HandleSomeEvent), sender, e);
}
else
{
// Event logic here.
}
}
This method first checks its InvokeRequired
boolean property, which also belongs to the ISynchronizeInvoke
interface, to see if it needs to marshal the event to its thread. If the property is true
, it calls the BeginInvoke
method, passing it a delegate to the method for handling the event and its arguments. If the property is false
, it executes its logic for responding to the event. In other words, the InvokeRequired
property will be true
if it is checked on a thread other than the one in which the Form
belongs; otherwise, it will be false
.
Note that the delegate being passed to BeginInvoke
represents the same method that handled the event in the first place. If the InvokeRequired
property is true
, this has the effect of invoking the event handler method twice: once when it initially is called in response to the event, and once after it has been marshaled by the Form
with a call to BeginInvoke
. The second time around, the InvokeRequired
property will be false
and the event logic will be run.
Using the SynchronizationContext Class
How do we write our own classes that use the SynchronizationContext
class? The key thing to remember is that our goal is to get the SynchronizationContext
belonging to the thread in which our class was created so that we can use it later from another thread to send/post events to the original thread. I'm going to give a really simple example. This example does nothing useful, but almost at a glance, it will show us the basic template for using the SynchronizationContext
class:
using System;using System.Threading;namespace SynchronizationContextExample{ public class MySynchronizedClass { private Thread workerThread; private SynchronizationContext context; public event EventHandler SomethingHappened; public MySynchronizedClass() { // It's important to get the current SynchronizationContext // object here in the constructor. We want the // SynchronizationContext object belonging to the thread in // which this object is being created. context = SynchronizationContext.Current; // It's possible that the current thread does not have a // SynchronizationContext object; a SynchronizationContext // object has not been set for this thread. // // If so, we simplify things by creating a SynchronizationContext // object ourselves. However! There could be some problems with // this approach. See the article for more details. if(context == null) { context = new SynchronizationContext(); } workerThread = new Thread(new ThreadStart(DoWork)); workerThread.Start(); } private void DoWork() { context.Post(new SendOrPostCallback(delegate(object state) { EventHandler handler = SomethingHappened; if(handler != null) { handler(this, EventArgs.Empty); } } } }}
This class gets the SynchronizationContext
for the current thread in its constructor. If this class is being used in a Form
, the current SynchronizationContext
object will allow us to post/send events to the Form
's thread. It's possible, however, that if an instance of this class is being created in, say, a worker thread somewhere, the SynchronizationContext.Current
property may be null
. In other words, the SynchronizationContext
object for the current thread may not have been set. So, it's important to check to see if the Current
property is null
. Here, in the case where it is null
, I just create an instance of the SynchronizationContext
class and rely on its default behavior.
What's nice is that our class doesn't have to know about who it's sending/posting events to. It doesn't have to have an ISynchronizeInvoke
object passed to it to synchronize itself with; it has access to the current SynchronizationContext
object through the SynchronizationContext.Current
property.
Warning! As was pointed out in a post to this article's message board, creating an instance of the SynchronizationContext
class can be dangerous. For example, say that you're writing a Form
based application and an object needs to interact with the main Form
in a thread safe way; the object needs access to the SynchronizationContext
that belongs to the Form
's thread. The object can retrieve this by accessing the SynchronizationContext.Current
property. This will give you the Form
's SynchronizationContext
derived object assuming that the Current
property is checked on the same thread in which the Form
is running. If it's checked from another thread, the Current
property will probably be null. If this is the case, it would be safer to treat this as an error rather than simply create an instance of the SynchronizationContext
class.
- 同步 SynchronizationContext
- SynchronizationContext
- 利用SynchronizationContext解决界面要素的线程同步问题
- 利用SynchronizationContext.Current在线程间同步上下文
- 利用SynchronizationContext.Current在线程间同步上下文
- 利用SynchronizationContext.Current在线程间同步上下文
- 利用SynchronizationContext.Current在线程间同步上下文
- 理解SynchronizationContext
- 理解SynchronizationContext
- Understanding SynchronizationContext
- 奇妙的SynchronizationContext
- 奇妙的SynchronizationContext
- 奇妙的SynchronizationContext
- SynchronizationContext.Post方法 代替
- 线程通讯(SynchronizationContext )
- 线程之间的通讯---SynchronizationContext
- 线程之间的通讯---SynchronizationContext
- Winform中SynchronizationContext的使用
- GIF解码和编码操作库源码(转载)
- 2008-5-25
- 心悬
- 谈判实录:地区品牌如何挤进强势卖场
- HTTP协议基础
- 同步 SynchronizationContext
- 一颗日本丸子的责任
- 求数组中第二大值
- 双击某个单元格,弹出窗体
- DLL的静态调用
- 匈牙利法的思考
- 系统中.exe可执行文件打不开手工解决办法
- eclipse下插件的安装,以VEditor 为例 (links方式安装)
- 在Java中运用Hashtable