除了“等待”之外,还有什么情况会允许同步代码被中断

本文关键字:许同步 同步 中断 代码 等待 之外 什么情况 除了 | 更新日期: 2023-09-27 17:56:46

我最近在我的异步代码中遇到了一个奇怪的错误。我在 COM 控件上调用了一个阻止方法,该方法似乎允许我的异步延续在阻塞时运行。

考虑示例代码(仅用于说明目的)

public async void Main()
{
    //assume some single threaded dispatcher. eg. WpfDispatcher
    Task doAsyncTask = DoAsync();
    Console.WriteLine("Start synchronous");
    CallSomeCOMControl();
    Console.WriteLine("End synchronous");
    await doAsyncTask;
}
public async Task DoAsync()
{
    Console.WriteLine("Start async");
    await Task.Delay(1);
    Console.WriteLine("End async");
}

在正常情况下,我希望以下输出:

Start async
Start synchronous
End synchronous
End async

我实际上看到的是:

Start async
Start synchronous
End async
End synchronous

现在我没有 COM 控件的源代码,但我知道这是一个非常古老的C++控件,没有异步/等待的概念。但是,它是一个 Active-X 控件。

我不知道 .Net RCW 的实现细节,但我假设必须进行某种消息泵送才能使控件正常工作。我还假设这种抽水允许我的延续运行。

我的假设正确吗?我是否应该知道我所谓的同步代码可能会被中断的任何其他情况?

除了“等待”之外,还有什么情况会允许同步代码被中断

这是很正常的,当调用越过公寓边界时,COM 会抽取。 它必须抽水,不这样做很可能导致死锁。 目前还不清楚为什么必须从代码段中跨越该边界,当您谈论 WPF 时,它看起来像一个 STA 线程。 可能是进程外服务器,也可能是在工作线程上创建了对象。

它与阻塞 STA 线程时 CLR 在 WaitOne() 或 Join() 调用上泵送的方式没有根本区别。 这导致的重入头痛与DoEvents()引起的痛苦非常相似。 COM和CLR泵都是有选择的,没有那么危险。 尽管高度没有记录。

COM 公寓大大简化了线程,解决了 98% 的常见问题。 最后2%给你一个分裂的偏头痛,可能非常难以解决,重新进入是这个列表的顶部。 解决此问题的唯一方法是不要将其留给 COM 为组件提供线程安全的主页并自己处理它。 使用这样的代码。

无论是否等待,当方法返回时,从DoAsync返回的任务已经启动。

而且您使用的延迟仅为 1 毫秒。

您是否尝试过更大的延迟?