Heim > Backend-Entwicklung > C++ > Wie können Deadlocks bei STA-Threads verhindert werden, wenn StaTaskScheduler mit blockierenden Wartezeiten verwendet wird?

Wie können Deadlocks bei STA-Threads verhindert werden, wenn StaTaskScheduler mit blockierenden Wartezeiten verwendet wird?

Barbara Streisand
Freigeben: 2025-01-11 11:08:42
Original
786 Leute haben es durchsucht

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

StaTaskScheduler und STA-Thread-Nachrichtenpumpen

Der StaTaskScheduler in ParallelExtensionsExtras vom Parallel-Team ist für das Hosten älterer STA COM-Objekte von Drittanbietern konzipiert. In der Implementierungsbeschreibung heißt es, dass sie MTA- und STA-Threads unterstützt und Unterschiede in zugrunde liegenden APIs wie WaitHandle.WaitAll verarbeitet.

Es ist jedoch falsch anzunehmen, dass der StaTaskScheduler eine Warte-API verwendet, die Nachrichten pumpt (z. B. CoWaitForMultipleHandles), um Deadlocks im STA-Thread zu verhindern. Der blockierende Teil der TPL pumpt möglicherweise keine Nachrichten weiter, was zu einem Deadlock führt.

In einem vereinfachten Szenario tritt das Problem auf, wenn das prozessinterne STA-COM-Objekt A das prozessinterne Objekt B aufruft und einen Rückruf von B erwartet. Der Aufruf von a.Method(b) kehrt nie zurück, da irgendwo innerhalb von BlockingCollection ein blockierender Wartestatus (kein Pumpen von Nachrichten) vorliegt.

Die Lösung besteht darin, einen benutzerdefinierten Synchronisierungskontext zu implementieren, der Nachrichten mithilfe von CoWaitForMultipleHandles explizit pumpt, und ihn auf jedem vom StaTaskScheduler gestarteten STA-Thread zu installieren.

MsgWaitForMultipleObjectsEx eignet sich besser zum Nachrichtenpumpen als CoWaitForMultipleHandles. Die Wait-Methode eines benutzerdefinierten Synchronisierungskontexts kann als Weiterleitung an SynchronizationContext.WaitHelper implementiert werden oder eine voll funktionsfähige Nachrichtenpumpschleife enthalten.

Der folgende Code demonstriert eine benutzerdefinierte Synchronisierungskontextimplementierung, die eine Message-Pump-Schleife enthält:

<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>
Nach dem Login kopieren

Durch die Verwendung dieses benutzerdefinierten Synchronisierungskontexts und der Nachrichtenpumpschleife wird sichergestellt, dass Nachrichten auch dann gepumpt werden, wenn blockierende Wartevorgänge im STA-Thread verwendet werden, und verhindert einen STA-Thread-Deadlock.

Das obige ist der detaillierte Inhalt vonWie können Deadlocks bei STA-Threads verhindert werden, wenn StaTaskScheduler mit blockierenden Wartezeiten verwendet wird?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage