原文地址:http://msdn.microsoft.com/zh-cn/magazine/gg598924.aspx

很遗憾,很多开发人员甚至不知道这个有用的工具。

无论是什么平台(ASP.NET、Windows 窗体、Windows Presentation Foundation (WPF)、Silverlight 或其他),所有 .NET 程序都包含 SynchronizationContext 概念,并且所有多线程编程人员都可以通过理解和应用它获益。

SynchronizationContext 的必要性

每个要以这种方式使用 Windows 消息队列的多线程程序都必须定义自己的自定义 Windows 消息以及处理约定。

ISynchronizeInvoke 诞生了。

Windows 窗体提供了唯一的 ISynchronizeInvoke 实现,并且开发了一种模式来设计异步组件,这样皆大欢喜。

使用异步页面,处理请求的线程可以开始每个操作,然后返回到 ASP.NET 线程池;当操作结束时,ASP.NET 线程池的另一个线程可以完成该请求。

经过精心设计,SynchronizationContext 取代了 ISynchronizeInvoke。

SynchronizationContext 的概念

设计 SynchronizationContext 是为了替代 ISynchronizeInvoke,但完成设计后,它就不仅仅是一个替代品了。

SynchronizationContext 不包含用来确定是否必须同步的机制,因为这是不可能的。

线程可以更改其当前上下文,但这样的情况非常少见。

大多数情况下,捕获到当前 SynchronizationContext 时,计数递增;捕获到的 SynchronizationContext 用于将完成通知列队到上下文中时,计数递减。

 中列出了一些最为重要的方面。

SynchronizationContext API 的各方面

  1.  
  2.           // The important aspects of the SynchronizationContext APIclass SynchronizationContext
  3.  
  4. {
  5.  
  6.   // Dispatch work to the context.
  7.           void Post(..); // (asynchronously)
  8.  
  9.   void Send(..); // (synchronously)
  10.  
  11.   // Keep track of the number of asynchronous operations.
  12.           void OperationStarted();
  13.  
  14.   void OperationCompleted();
  15.  
  16.   // Each thread has a current context.
  17.           // If "Current" is null, then the thread's current context is
  18.  
  19.  
  20.   // "new SynchronizationContext()", by convention.
  21.           static SynchronizationContext Current { get; }
  22.  
  23.   static void SetSynchronizationContext(SynchronizationContext);
  24. }
  25.         

SynchronizationContext 的实现

我将简单讨论部分实现。

WindowsFormsSynchronizationContext 的上下文是一个单独的 UI 线程。

当前实现为每个 UI 线程创建一个 WindowsFormsSynchronizationContext。

DispatcherSynchronizationContext 的上下文是一个单独的 UI 线程。

当前实现为每个顶层窗口创建一个 DispatcherSynchronizationContext,即使它们都使用相同的基础调度程序也是如此。

根据惯例,如果一个线程的当前 SynchronizationContext 为 null,那么它隐式具有一个默认 SynchronizationContext。

 线程。

因此,UI 应用程序通常有两个同步上下文:包含 UI 线程的 UI SynchronizationContext 和包含 ThreadPool 线程的默认 SynchronizationContext。

图 2)。

[转]SynchronizationContext 综述

UI 上下文中只有一个 BackgroundWorker

图 3)。

[转]SynchronizationContext 综述

UI 上下文中的嵌套 BackgroundWorker

nitoasync.codeplex.com) 可用作通用 SynchronizationContext 实现。

即使委托是通过调用 Post“异步”列队的,也会直接调用委托。

这些可能是启动请求的线程,但更可能是操作完成时处于空闲状态的任何线程。

它们可以在任意线程上执行,但该线程将具有原始页面的标识和区域。

该上下文将保持在相同的线程中,但会确保事件处理程序使用正确的标识和区域运行。

有关 SynchronizationContext 实现的注意事项

但是,在设计这类可重用组件时,必须注意几点。

不过,这不是多大的缺点;代码更为清晰,并且更容易验证它是否始终在已知上下文中执行,而不是试图处理多个上下文。

默认 SynchronizationContext 不保证执行顺序或同步顺序。

一般而言,最好不要假设任何上下文实例将在任何指定线程上运行。

 总结了这些不同的实现。

SynchronizationContext 实现摘要

  使用特定线程执行委托 独占(一次执行一个委托) 有序(委托按队列顺序执行) Send 可以直接调用委托 Post 可以直接调用委托
Windows 窗体 如果从 UI 线程调用 從不
WPF/Silverlight 如果从 UI 线程调用 從不
默认 不能 不能 不能 Always 從不
ASP.NET 不能 不能 Always Always

AsyncOperationManager 和 AsyncOperation

AsyncOperation 将委托异步发布到捕获的 SynchronizationContext。

对于这些类型的操作,可以直接捕获和使用 SynchronizationContext。

基于任务的 API 是 .NET 中异步编程的发展方向。

SynchronizationContext 的库支持示例

通过使用 SynchronizationContext 公开 API,库不仅获得了框架独立性,而且为高级最终用户提供了一个可扩展点。

当恢复 ExecutionContext 时,通常也会恢复 SynchronizationContext。

此特性的默认值为 true,这表示在创建通信通道时捕获当前 SynchronizationContext,这一捕获的 SynchronizationContext 用于使约定方法列队。

在这类情况下,将 UseSynchronizationContext 设置为 false 可以禁止 WCF 自动使用 SynchronizationContext。

msdn.microsoft.com/magazine/cc163321)。

部分 .NET Framework 4 升级在 WorkflowInstance 类及其派生类 derived WorkflowApplication 上包含 SynchronizationContext 属性。

然后该 SynchronizationContext 用于发布工作流完成事件以及工作流活动。

 所示。

UI 更新的进度报告

  1.  
  2.           private void button1_Click(object sender, EventArgs e)
  3. {
  4.   // This TaskScheduler captures SynchronizationContext.Current.
  5.           TaskScheduler taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
  6.   // Start a new task (this uses the default TaskScheduler, 
  7.   // so it will run on a ThreadPool thread).
  8.           Task.Factory.StartNew(() =>
  9.   {
  10.     // We are running on a ThreadPool thread here.
  11.           ; // Do some work.
  12.           // Report progress to the UI.
  13.           Task reportProgressTask = Task.Factory.StartNew(() =>
  14.       {
  15.         // We are running on the UI thread here.
  16.           ; // Update the UI with our progress.
  17.           },
  18.       CancellationToken.None,
  19.       TaskCreationOptions.None,
  20.       taskScheduler);
  21.     reportProgressTask.Wait();
  22.   
  23.     ; // Do more work.
  24.           });
  25. }
  26.         

如果出现取消请求,CancellationToken 将该委托列入 SynchronizationContext 队列而不是直接执行它。

ObserveOn 通常用于使用传入事件更新 UI,SubscribeOn 用于从 UI 对象使用事件。

Rx 包含 SynchronizationContextScheduler,这是一个列入 SynchronizationContext 的 IScheduler 实现。

仅当它不为 null 时,才捕获当前 SynchronizationContext,如果为 null,则捕获当前 TaskScheduler):

  1.  
  2.           private async void button1_Click(object sender, EventArgs e)
  3. {
  4.   // SynchronizationContext.Current is implicitly captured by await.
  5.           var data = await webClient.DownloadStringTaskAsync(uri);
  6.  
  7.   // At this point, the captured SynchronizationContext was used to resume
  8.   // execution, so we can freely update UI objects.
  9.           }
  10.         

SynchronizationContext 实例还有一种扩展方法 SwitchTo;使用该方法,任何异步方法都可以通过调用 SwitchTo 并等待结果,更改为不同的 SynchronizationContext。

该类在构造时捕获当前 SynchronizationContext 并在此上下文中引发其 ProgressChanged 事件。

这一行为使返回 void 的异步方法类似于顶层异步操作。

限制和功能

技术精湛的编程人员了解 SynchronizationContext 限制和功能后,可以更好地编写和利用这些类。

 

nitoprograms.com。

相关文章:

  • 2021-10-14
  • 2021-10-23
  • 2021-09-07
  • 2021-09-14
  • 2021-09-21
  • 2021-10-08
  • 2022-03-03
猜你喜欢
  • 2022-01-24
  • 2021-08-14
  • 2021-10-28
  • 2022-12-23
  • 2021-07-13
  • 2022-12-23
相关资源
相似解决方案