如何创建自定义 SynchronizationContext 以便所有延续都可以由我自己的单线程事件循环处理?

问题描述 投票:0回答:1

假设您正在编写一个自定义单线程 GUI 库(或任何具有事件循环的库)。据我了解,如果我使用

async/await
,或者只是常规 TPL 延续,它们都将安排在
TaskScheduler.Current
(或
SynchronizationContext.Current
)。

问题在于延续可能想要访问库的单线程部分,这意味着它必须在同一个事件循环中执行。例如,给定一个简单的游戏循环,事件可能会像这样处理:

// All continuation calls should be put onto this queue
Queue<Event> events;

// The main thread calls the `Update` method continuously on each "frame"
void Update() {
    // All accumulated events are processed in order and the queue is cleared
    foreach (var event : events) Process(event);

    events.Clear();
}

现在鉴于我的假设是正确的并且 TPL 使用

SynchronizationContext.Current
,应用程序中的任何代码都应该能够执行以下操作:

async void Foo() {
    someLabel.Text = "Processing";

    await BackgroundTask();

    // This has to execute on the main thread
    someLabel.Text = "Done";
}

这让我想到了这个问题。 如何实现自定义

SynchronizationContext
以允许我在自己的线程上处理延续? 这是否是正确的方法?

c# multithreading asynchronous async-await
1个回答
16
投票

实现自定义

SynchronizationContext
并不是世界上最简单的事情。我有一个开源单线程实现here,您可以将其用作起点(或者可能只是用来代替主循环)。

默认情况下,

AsyncContext.Run
需要单个委托来执行并在完全完成时返回(因为
AsyncContext
使用自定义
SynchronizationContext
,它能够等待
async void
方法以及常规异步/同步代码) ).

AsyncContext.Run(async () => await DoSomethingAsync());

如果您想要更大的灵活性,您可以使用

AsyncContext
高级成员(这些不会显示在 IntelliSense 中,但它们在那里)来保持上下文处于活动状态,直到出现一些外部信号(例如“退出帧”):

using (var context = new AsyncContext())
{
  // Ensure the context doesn't exit until we say so.
  context.SynchronizationContext.OperationStarted();

  // TODO: set up the "exit frame" signal to call `context.SynchronizationContext.OperationCompleted()`
  // (note that from within the context, you can alternatively call `SynchronizationContext.Current.OperationCompleted()`

  // Optional: queue any work you want using `context.Factory`.

  // Run the context; this only returns after all work queued to this context has completed and the "exit frame" signal is triggered.
  context.Execute();
}

AsyncContext
Run
Execute
在运行时替换当前的
SynchronizationContext
,但它们会保存原始上下文并在返回之前将其设置为当前上下文。这使它们能够以嵌套方式很好地工作(例如“框架”)。

(我假设“框架”是指一种类似 WPF 的调度程序框架)。

© www.soinside.com 2019 - 2024. All rights reserved.