前言
什么是同步线程上下文呢?
这里面有一些需求,就是有些代码需要在同一个线程运行。
避免一些并发问题啥的。
正文
例子:
自定义上下文:- public class SingleThreadSynchronizationContext : SynchronizationContext, IDisposable
- {
- private readonly BlockingCollection<(SendOrPostCallback Callback, object State)> _queue = new();
- private readonly Thread _processingThread;
- public SingleThreadSynchronizationContext()
- {
- _processingThread = new Thread(ProcessQueue)
- {
- IsBackground = true,
- Name = "SingleThreadSynchronizationContext Thread"
- };
- _processingThread.Start();
- }
- // 异步方式派发工作
- public override void Post(SendOrPostCallback d, object state)
- {
- _queue.Add((d, state));
- }
- // 同步方式派发工作(可能阻塞)
- public override void Send(SendOrPostCallback d, object state)
- {
- if (Thread.CurrentThread == _processingThread)
- {
- d(state); // 如果已经在目标线程,直接执行
- }
- else
- {
- using var signal = new ManualResetEventSlim();
- Post(_ =>
- {
- d(_);
- signal.Set();
- }, state);
- signal.Wait();
- }
- }
- private void ProcessQueue()
- {
- // 设置当前线程的上下文
- SetSynchronizationContext(this);
- Console.WriteLine(SynchronizationContext.Current == null);
- Console.WriteLine($"ProcessQueue: {Thread.CurrentThread.ManagedThreadId}");
- foreach (var work in _queue.GetConsumingEnumerable())
- {
- work.Callback(work.State);
- }
- }
- public void Dispose()
- {
- _queue.CompleteAdding();
- _processingThread.Join();
- _queue.Dispose();
- }
- }
复制代码 然后去取:- static async Task Main()
- {
- Console.WriteLine($"Main Thread: {Thread.CurrentThread.ManagedThreadId}");
- // 创建并设置自定义上下文
- using var context = new SingleThreadSynchronizationContext();
- SynchronizationContext.SetSynchronizationContext(context);
- // 演示异步操作如何回到特定线程
- await Task.Run(() =>
- {
- Console.WriteLine(SynchronizationContext.Current == null);
- Console.WriteLine($"Task.Run Thread: {Thread.CurrentThread.ManagedThreadId}");
- }).ConfigureAwait(true);
- Console.WriteLine($"After await Thread: {Thread.CurrentThread.ManagedThreadId}");
- // 演示Send/Post区别
- context.Post(_ =>
- {
- Console.WriteLine($"Post Thread: {Thread.CurrentThread.ManagedThreadId}");
- }, null);
- context.Send(_ =>
- {
- Console.WriteLine($"Send Thread: {Thread.CurrentThread.ManagedThreadId}");
- }, null);
- Console.WriteLine("All operations completed");
-
- Console.ReadKey();
- }
复制代码 这样就可以同步上下文了,也就是在指定的上下文中执行了。
taskschedule 方式:- // 自定义单线程任务调度器
- public class SingleThreadTaskScheduler : TaskScheduler, IDisposable
- {
- private readonly BlockingCollection<Task> _tasks = new();
- private readonly Thread _thread;
- public SingleThreadTaskScheduler(string threadName = null)
- {
- _thread = new Thread(() =>
- {
- foreach (var task in _tasks.GetConsumingEnumerable())
- {
- TryExecuteTask(task);
- }
- })
- {
- IsBackground = true,
- Name = threadName ?? "SingleThreadTaskScheduler"
- };
- _thread.Start();
- }
- protected override IEnumerable<Task> GetScheduledTasks() => _tasks.ToArray();
- protected override void QueueTask(Task task) => _tasks.Add(task);
- protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) =>
- Thread.CurrentThread == _thread && TryExecuteTask(task);
- public void Dispose()
- {
- _tasks.CompleteAdding();
- _thread.Join();
- }
- }
- // 使用示例
- async Task RunWithTaskScheduler()
- {
- using var scheduler = new SingleThreadTaskScheduler("CustomTaskSchedulerThread");
-
- await Task.Factory.StartNew(async () =>
- {
- Console.WriteLine($"Current Thread: {Thread.CurrentThread.Name}");
- await Task.Delay(100);
- Console.WriteLine($"Still on thread: {Thread.CurrentThread.Name}");
- }, CancellationToken.None, TaskCreationOptions.None, scheduler).Unwrap();
- }
复制代码 这里面是原理,然后呢?实际上,有一个东西是taskschedule 默认给我们提供了一个同步的上下文的调度器。- internal sealed class MyForm : Form {
- private readonly TaskScheduler m_syncContextTaskScheduler;
- public MyForm() {
- // 获得对一个同步上下文任务调度器的引用
- m_syncContextTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
- Text = "Synchronization Context Task Scheduler Demo";
- Visible = true; Width = 400; Height = 100;
- }
- private CancellationTokenSource m_cts;
- protected override void OnMouseClick(MouseEventArgs e) {
- if (m_cts != null) { // 一个操作正在进行,取消它
- m_cts.Cancel();
- m_cts = null;
- } else { // 操作没有开始,启动它
- // 操作没有开始,启动它
- Text = "Operation running";
- m_cts = new CancellationTokenSource();
- // 这个任务使用默认任务调度器,在一个线程池线程上执行
- Task<Int32> t = Task.Run(() => Sum(m_cts.Token, 20000), m_cts.Token);
- // 这些任务使用同步上下文任务调度器,在 GUI 线程上执行
- t.ContinueWith(task => Text = "Result: " + task.Result,
- CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, m_syncContextTaskScheduler);
- t.ContinueWith(task => Text = "Operation canceled",
- CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, m_syncContextTaskScheduler);
- t.ContinueWith(task => Text = "Operation faulted",
- CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, m_syncContextTaskScheduler);
- }
- base.OnMouseClick(e);
- }
- }
复制代码 是的就是这个:TaskScheduler.FromCurrentSynchronizationContext(), 差不多和上面写的一样,可以自行去阅读源码
结
同步上下文大概就是这么回事,不是去线程池同步上下文,线程池最好是没有上下文的,这样才符合上下文的特征。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |