c# - 除了 "await"之外还有哪些情况会允许同步代码被中断

标签 c# com async-await activex rcw

我最近在我的异步代码中遇到了一个奇怪的错误。我在 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 线程。可能是进程外服务器,也可能是您在工作线程上创建了对象。

这与 CLR 在您阻塞 STA 线程时调用 WaitOne() 或 Join() 的方式没有根本区别。这引起的重入问题与 DoEvents() 引起的痛苦非常相似。尽管 COM 和 CLR 都有选择性地泵送,但并不那么危险。尽管高度未记录。

COM 单元极大地简化了线程处理,解决了 98% 的常见问题。最后 2% 会给你带来极度难以解决的 split 性偏头痛,重新进入是该列表的首位。解决这个问题的唯一方法是不要让 COM 为组件提供线程安全的家并自己处理它。用code like this .

关于c# - 除了 "await"之外还有哪些情况会允许同步代码被中断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30887643/

相关文章:

c# - Excel 在 *.xlsx 中发现不可读的内容

c# - 获得对 C# 组件中鼠标点击的访问权限

windows - 在 Windows 资源管理器中预览 matlab 图形(将图像设置为另一个文件的缩略图的实用程序)

c# - Excel.Workbook.SaveAs(...) 同名文件

c# - 模拟一个抛出异常(moq)的方法,但在其他方面表现得像被模拟的对象?

c# - Entity Framework 中复杂类型属性名称的别名

c++ - 如何确保无法重入访问我的主 STA COM 服务器 (C++)?

c# - 为什么没有 SqlDataReader.ReadAsync() 接口(interface)

c# - 绕过我的头等待异步和 NHibernate

c# - 如何在 NUnit 中测试此 View 模型的异步行为?