SynchronizationContext

介绍

SynchronizationContext允许一个线程和另外一个线程进行通讯,SynchronizationContext在通讯中充当传输者的角色。另外这里有个地方需要清楚的,不是每个线程都附加SynchronizationContext这个对象,只有UI线程是一直拥有的。

SynchronizationContext.Current 能得到当前被主UI线程接管过的对象SynchronizationContext。

这个对象有一个方法:SynchronizationContext.Send(SendOrPostCallback d,object state)

  • d 为一个没有返回值,并且具有一个Object类型传入参数的委托(SendOrPostCallback )
  • state 为执行这个委托时的参数(object)

你现在需要在子线程运行的时候利用SynchronizationContext.Current 得到SynchronizationContext对象,然后在需要切回UI线程的地方使用:SynchronizationContext.Send(SendOrPostCallback d,object state);就可实现将委托的方法切回到UI线程上去执行。
注意:SynchronizationContext的对象不是所有线程都被附加的,只有UI主线程会被附加。

对于UI线程来说,是如何将SynchronizationContext这个对象附加到线程上的呢?
在Form1 form = new Form1()之前,SynchronizationContext对象是为空,

而当实例化Form1窗体后,SynchronizationContext对象就被附加到这个线程上了。

所以可以得出答案了:

当Control对象被创建的同时,SynchronizationContext对象也会被创建并附加到线程上。

所以在使用时,一定要等窗体InitializeComponent(); 这个完成后 它才能得到一个不为NULL的对象。

Send()和Post()区别

  • Send() 是简单的在当前线程上去调用委托来实现(同步调用)。也就是在子线程上直接调用UI线程执行,等UI线程执行完成后子线程才继续执行。【常见的应用场景是:后台线程执行任务时,需要UI弹MessageBox,并等待用户做选择时,用Send方法即可】
  • Post() 是在线程池上去调用委托来实现(异步调用)。这是子线程会从线程池中找一个线程去调UI线程,子线程不等待UI线程的完成而直接执行自己下面的代码。

Send方法详细解释

`SynchronizationContext.Send()` 方法是在同步上下文(SynchronizationContext)上执行操作的方法。在C#中,可以通过这个方法将一个操作推到同步上下文的消息队列中,使其在该上下文的线程中同步执行。
`SynchronizationContext.Send()` 方法接受两个参数:一个表示要执行的操作的委托,另一个表示操作所需的状态对象。该方法将状态对象封装在回调委托中并将其加入同步上下文的消息队列中,等待该上下文有空闲时执行。

class MyClass {
    private readonly SynchronizationContext context;
    public MyClass(SynchronizationContext context) {
        this.context = context;
    }
    public void SomeMethod() {
        context.Send(state => {
            // state 表示之前的状态对象
            // 在这里执行需要同步执行的操作
        }, null);
    }
}

在上面的代码中,我们创建了一个名为 `MyClass` 的类,并使用 `context`(SynchronizationContext)在方法 `SomeMethod()` 中同步执行操作。我们使用 `context.Send()` 方法将操作添加到同步上下文的消息队列中,并等待执行。
需要注意的是,`context.Send()` 方法会阻塞当前线程,直到该操作完成为止。如果你希望在后台线程中执行该操作,可以使用 `context.Post()` 方法,该方法会将操作放在消息队列中等待执行,但不会阻塞当前线程。
总之,SynchronizationContext.Send() 方法允许将操作同步地添加到同步上下文的消息队列中,并等待该上下文有空闲时执行。使用 Send() 方法时,需要注意在同步上下文的线程中执行操作,以避免阻塞 UI 线程等问题。

参考

利用SynchronizationContext.Current在线程间同步上下文

线程中更新ui- SynchronizationContext-Post/Send方法-简单实验

 

posted @ 2023-07-12 16:55  peterYong  阅读(176)  评论(0编辑  收藏  举报