C# SynchronizationContext以及Send和Post使用总结

发布时间 2023-11-06 23:44:15作者: 凯帝农垦

1、(SynchronizationContext)同步上下文的作用

SynchronizationContext 顾名思义是同步上下文的意思。利用此对象可以实现线程间数据的同步、异步访问 ,其实就是实现线程之间通讯的。

SynchronizationContext(同步上下文),是一个抽象类,它表示线程上下文,用于协调异步方法(或代理线程)的回调。

使用同步上下文可以使得异步方法(或代理线程)的回调在正确的线程上下文中进行,这样可以避免由于线程上下文切换引发的问题,同时可以更好地掌控异步操作的生命周期。

其实,同步上下文是一种编程模型,它允许多个线程之间的协作,使得程序员可以更加轻松地编写异步代码。

 class Program
    {

       static Thread _workThread;
       static SynchronizationContext _mainThreadSynContext;

        static void Main(string[] args)
        {
            _mainThreadSynContext = SynchronizationContext.Current;

            if (_mainThreadSynContext == null)
            {
                _mainThreadSynContext = new SynchronizationContext();
            }

            _workThread = new Thread(new ThreadStart(DoWork));

            _workThread.Start();

            Console.ReadLine();
        }

        static void DoWork()
        {
            int a = 10;
            _mainThreadSynContext.Post(new SendOrPostCallback(ThreadCallBack),a);
        }

        static void ThreadCallBack(object state)
        {
           Console.WriteLine((int)state);

            Console.ReadLine();
        }
    }

 

2、创建(SynchronizationContext)同步上下文的方法

1)直接new创建一个SynchronizationContext同步上下文对象。
2)winform程序通过SynchronizationContext.Current获取UI线程的同步上下文对象。
3)AsyncOperation和AsyncOperationManager类来操作同步上下文对象,不直接访问同步上下文对象(SynchronizationContext),推荐这程方法。

 

3、(SynchronizationContext)同步上下文的Send和Post方法

看了一些解释Send和Post方法,感觉弄得很复杂,我感觉其实简单来说,

1)Send方法就是同步调用,在当前线程上调用委托。
2)Post方法就是异步调用,在线程池中的线程调用委托。

4、示例代码

1)(SynchronizationContext)同步上下文使用示例代码

using System;
using System.Threading;
namespace SynchronizationContextExample
{
    public class MySynchronizedClass
    {
        private Thread workerThread;
        private SynchronizationContext context;
        public event EventHandler SomethingHappened;
        public MySynchronizedClass()
        {
         //获取当前SynchronizationContext非常重要对象在构造函数中。我们想要的
         //属于线程的SynchronizationContext对象
         //这个对象正在被创建。
         //context= SynchronizationContext.Current;当前线程可能没有SynchronizationContext对象;该线程尚未为设置SynchronizationContext对象。
         //如果是这样,我们可以通过创建SynchronizationContext来简化
            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);
                }
            }), null);
        }
    }
}

2)使用AsyncOperation和AsyncOperationManager类示例代码

using System;
using System.Threading;
using System.ComponentModel;
namespace SynchronizationContextExample
{
    public class MySynchronizedClass
    {
        private Thread workerThread;
        private AsyncOperation operation;
        public event EventHandler SomethingHappened;
        public MySynchronizedClass()
        {
            operation = AsyncOperationManager.CreateOperation(null);
            workerThread = new Thread(new ThreadStart(DoWork));
            workerThread.Start();
        }
        
        private void DoWork()
        {
            operation.Post(new SendOrPostCallback(delegate(object state)
            {
                EventHandler handler = SomethingHappened;
                if(handler != null)
                {
                    handler(this, EventArgs.Empty);
                }
            }), null);
            operation.OperationCompleted();
        }
    }
}

 

在编写异步代码时,同步上下文是一个非常重要的概念。它可以确保异步操作的回调在正确的线程上下文中执行,同时可以更加轻松地编写可读、可维护的异步代码。在.NET中,常见的同步上下文类型包括WindowsFormsSynchronizationContext、TaskScheduler、AspNetSynchronizationContext等。

WindowsFormsSynchronizationContext主要用于Windows Forms应用程序。当异步操作完成时,它会将结果返回到主线程,使得我们可以更新UI。

// 创造同步上下文
SynchronizationContext ctx =
    WindowsFormsSynchronizationContext.Current;

// 异步操作
var result = await Task.Run(() =>
{
    return SomeLongOperation();
});  

// 回调到主线程
ctx.Post(state =>
{
    textBox1.Text = result.ToString();
}, null);

2、TaskScheduler

TaskScheduler是一个线程池,当异步任务完成时,它会使用回调线程池来处理异步回调。

// 创造同步上下文
var scheduler = TaskScheduler.FromCurrentSynchronizationContext(); 

// 异步操作
Task.Run(() =>
{
    return SomeLongOperation();
})
.ContinueWith(task =>
{
    // 处理结果
    textBox1.Text = task.Result.ToString();
}, CancellationToken.None, TaskContinuationOptions.None, scheduler);

3、AspNetSynchronizationContext

AspNetSynchronizationContext主要用于ASP.Net应用程序。当异步操作完成时,它会将结果返回到AspNet请求处理程序中,使得我们可以更新Web UI。

 
// 创造同步上下文
SynchronizationContext ctx = new AspNetSynchronizationContext();

// 异步操作
var result = await Task.Run(() =>
{
    return SomeLongOperation();
});

// 回调
ctx.Post(state => {
    Response.Write(result.ToString());
}, null);

与async/await的结合使用

同步上下文可以与async/await一起使用,这样可以使得异步代码更加可读、可维护。

private async void Button_Click(object sender, RoutedEventArgs e)
{
    // 运行异步方法
    var result = await LongOperationAsync();

    // 更新UI
    Label.Content = result.ToString();
}

private async Task LongOperationAsync()
{
    // 访问网络
    await Task.Delay(TimeSpan.FromSeconds(5));

    // 返回结果
    return 42;
}