首页 > 后端开发 > C++ > 使用带有阻塞等待的 StaTaskScheduler 时,如何防止 STA 线程出现死锁?

使用带有阻塞等待的 StaTaskScheduler 时,如何防止 STA 线程出现死锁?

Barbara Streisand
发布: 2025-01-11 11:08:42
原创
786 人浏览过

How Can Deadlocks Be Prevented on STA Threads When Using StaTaskScheduler with Blocking Waits?

StaTaskScheduler 和 STA 线程消息泵送

来自并行团队的 ParallelExtensionsExtras 中的 StaTaskScheduler 旨在托管第三方提供的旧版 STA COM 对象。实现说明指出,它支持 MTA 和 STA 线程,并处理底层 API(如 WaitHandle.WaitAll)的差异。

然而,假设 StaTaskScheduler 会使用一个泵送消息的等待 API(例如 CoWaitForMultipleHandles)来防止 STA 线程上的死锁是不正确的。TPL 的阻塞部分可能不会泵送消息,从而导致死锁。

在一个简化的场景中,进程内 STA COM 对象 A 调用进程外对象 B 并期望从 B 获取回调,问题就出现了。由于 BlockingCollection 内部某个地方的阻塞等待(不泵送消息),对 a.Method(b) 的调用永远不会返回。

解决方案是实现一个自定义同步上下文,该上下文使用 CoWaitForMultipleHandles 显式泵送消息,并将其安装在 StaTaskScheduler 启动的每个 STA 线程上。

MsgWaitForMultipleObjectsEx 比 CoWaitForMultipleHandles 更适合消息泵送。自定义同步上下文的 Wait 方法可以实现为转发到 SynchronizationContext.WaitHelper 或包含一个功能齐全的消息泵送循环。

以下代码演示了一个包含消息泵送循环的自定义同步上下文实现:

<code class="language-c#">// 核心循环
var msg = new NativeMethods.MSG();
while (true)
{
    // 带有 MWMO_INPUTAVAILABLE 的 MsgWaitForMultipleObjectsEx 返回,
    // 即使消息队列中已经看到但未删除消息
    nativeResult = NativeMethods.MsgWaitForMultipleObjectsEx(
        count, waitHandles,
        (uint)remainingTimeout,
        QS_MASK,
        NativeMethods.MWMO_INPUTAVAILABLE);

    if (IsNativeWaitSuccessful(count, nativeResult, out managedResult) || WaitHandle.WaitTimeout == managedResult)
        return managedResult;

    // 有消息,泵送并分派它
    if (NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, NativeMethods.PM_REMOVE))
    {
        NativeMethods.TranslateMessage(ref msg);
        NativeMethods.DispatchMessage(ref msg);
    }
    if (hasTimedOut())
        return WaitHandle.WaitTimeout;
}</code>
登录后复制

使用此自定义同步上下文和消息泵送循环可确保即使在 STA 线程上使用阻塞等待时也能泵送消息并防止 STA 线程死锁。

以上是使用带有阻塞等待的 StaTaskScheduler 时,如何防止 STA 线程出现死锁?的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板