c#同步上下文SynchronizationContext学习笔记

本文介绍了同步上下文的基本功能及其在不同同步模型中的作用。详细解释了如何通过SynchronizationContext进行同步消息调度,并提供了使用同步上下文更新WinForms和WPF UI内容的方法。



https://www.cnblogs.com/weifeng123/p/10039100.html

提供在各种同步模型中传播同步上下文的基本功能。同步上下文的工作就是确保调用在正确的线程上执行。

同步上下文的基本操作

Current 获取当前同步上下文

var context = SynchronizationContext.Current;

Send 一个同步消息调度到一个同步上下文。

SendOrPostCallback callback = o =>
                                 {
                                     //TODO:
                                 };
context.Send(callback,null);

send调用后会阻塞直到调用完成。 
Post 将异步消息调度到一个同步上下文。

SendOrPostCallback callback = o =>
                                {
                                      //TODO:
                                };
context.Post(callback,null);

  和send的调用方法一样,不过Post会启动一个线程来调用,不会阻塞当前线程。

使用同步上下文来更新UI内容

无论WinFromsWPF都只能用UI线程来更新界面的内容

常用的调用UI更新方法是Inovke(WinFroms):

private void button_Click(object sender, EventArgs e)
{
       ThreadPool.QueueUserWorkItem(BackgroudRun);
}

private void BackgroudRun2(object state)
{
            this.Invoke(new Action(() =>
                       {
                          label1.Text = "Hello Invoke";
                       }));
}

使用同步上下文也可以实现相同的效果,WinFroms和WPF继承了SynchronizationContext,使同步上下文能够在UI线程或者Dispatcher线程上正确执行

System.Windows.Forms. WindowsFormsSynchronizationContext
System.Windows.Threading. DispatcherSynchronizationContext

调用方法如下:

private void button_Click(object sender, EventArgs e)
{
           var context = SynchronizationContext.Current; //获取同步上下文
           Debug.Assert(context != null);
           ThreadPool.QueueUserWorkItem(BackgroudRun, context); 
}

private void BackgroudRun(object state)
{
    var context = state as SynchronizationContext; //传入的同步上下文
    Debug.Assert(context != null);
    SendOrPostCallback callback = o =>
                                      {
                                          label1.Text = "Hello SynchronizationContext";
                                      };
    context.Send(callback,null); //调用
}

使用.net4.0的Task 可以简化成

private void button_Click(object sender, EventArgs e)
{
            var  scheduler = TaskScheduler.FromCurrentSynchronizationContext(); // 创建一个SynchronizationContext 关联的 TaskScheduler
            Task.Factory.StartNew(() => label1.Text = "Hello TaskScheduler", CancellationToken.None,
                                  TaskCreationOptions.None, scheduler);
}

### 同步上下文概念及使用详解 同步上下文SynchronizationContext)是 .NET 中用于控制代码在特定上下文中执行的重要机制,尤其在异步编程中,它决定了异步操作完成后如何调度回原始上下文(如 UI 线程)执行后续逻辑。同步上下文通过 `Post` 和 `Send` 方法实现对线程的调度,确保某些代码在特定线程(如 UI 线程)上运行,避免跨线程访问异常[^1]。 在 WinForm 或 WPF 等 UI 框架中,UI 线程拥有一个默认的同步上下文对象,可以通过 `SynchronizationContext.Current` 获取当前线程的同步上下文。在 UI 程序中,异步操作完成后通常需要回到 UI 线程更新界面,此时同步上下文会将回调调度到 UI 线程上执行。例如: ```csharp SynchronizationContext context = SynchronizationContext.Current; Task.Run(() => { // 模拟后台操作 Thread.Sleep(1000); // 回到原始上下文执行 context.Post(state => { Console.WriteLine("更新 UI 线程"); }, null); }); ``` 同步上下文的创建方式包括直接实例化 `SynchronizationContext` 对象、通过 `SynchronizationContext.Current` 获取当前上下文,或者使用 `AsyncOperation` 和 `AsyncOperationManager` 类进行封装操作。在 UI 应用程序中,推荐使用 `AsyncOperationManager` 来管理同步上下文,以避免直接操作上下文对象带来的复杂性和潜在错误[^2]。 同步上下文不仅影响异步任务的执行调度,还与 `async/await` 语法密切相关。当使用 `await` 等待一个任务时,如果当前线程有同步上下文(如 UI 线程),默认情况下 `await` 之后的代码会尝试回到原始上下文继续执行。可以通过 `ConfigureAwait(false)` 明确指定不捕获上下文,从而避免不必要的上下文切换,提高性能并减少死锁风险。 例如: ```csharp public async Task DoWorkAsync() { await SomeOperationAsync().ConfigureAwait(false); // 此部分代码不会强制回到原始上下文执行 } ``` 在多线程环境中,同步上下文还与线程同步机制(如 `lock`、`Monitor`、`Mutex`)共同作用,确保资源访问的顺序和一致性。尽管同步上下文本身不提供线程同步功能,但它决定了异步回调的执行线程,进而影响同步机制的行为[^4]。 ### 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值