首頁 >後端開發 >C++ >使用帶有阻塞等待的 StaTaskScheduler 時,如何防止 STA 執行緒出現死鎖?

使用帶有阻塞等待的 StaTaskScheduler 時,如何防止 STA 執行緒出現死鎖?

Barbara Streisand
Barbara Streisand原創
2025-01-11 11:08:42790瀏覽

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中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn