我最近在异步代码中遇到了一个奇怪的错误。我在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 ++控件,它没有async / await的概念。但它是一个Active-X控件。
我不知道.Net RCW的实现细节,但我假设必须继续进行某种消息处理才能使控件正常工作。我也假设这种抽吸允许我继续运行。
我的假设是否正确?在我应该知道的任何其他情况下,我所谓的同步代码会被中断吗?
答案 0 :(得分:3)
这很正常,当电话穿过公寓边界时,COM会抽水。它必须泵,不这样做很可能导致死锁。目前还不清楚为什么必须从片段中划分出边界,当你谈论WPF时,看起来就像一个STA线程。可能是进程外服务器,可能是您在工作线程上创建了对象。
与阻止STA线程时CLR在WaitOne()或Join()调用上的方式没有根本区别。这引起的重新头痛与DoEvents()引起的痛苦非常相似。 COM和CLR都选择性地泵送,但不是那么危险。虽然高度无证。
COM公寓极大地简化了线程,解决了98%的常见问题。最后2%给你一个分裂的偏头痛,这可能是非常难以解决的,重新入侵是该列表的顶部。解决这个问题的唯一方法就是不要让COM为组件提供一个线程安全的家庭并自己处理它。使用code like this。答案 1 :(得分:0)
独立于等待与否,DoAsync
返回的任务在方法返回时已经开始。
你使用的延迟只有1毫秒。
你有没有尝试过更大的延迟?