Maison >développement back-end >C++ >Comment éviter les blocages sur les threads STA lors de l'utilisation de StaTaskScheduler avec des attentes de blocage ?

Comment éviter les blocages sur les threads STA lors de l'utilisation de StaTaskScheduler avec des attentes de blocage ?

Barbara Streisand
Barbara Streisandoriginal
2025-01-11 11:08:42794parcourir

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

Pompage des messages StaTaskScheduler et STA

Le StaTaskScheduler dans ParallelExtensionsExtras de l'équipe Parallel est conçu pour héberger les anciens objets STA COM fournis par des tiers. La description de l'implémentation indique qu'elle prend en charge les threads MTA et STA et gère les différences dans les API sous-jacentes telles que WaitHandle.WaitAll.

Cependant, il est incorrect de supposer que StaTaskScheduler utilisera une API d'attente qui pompe les messages (tels que CoWaitForMultipleHandles) pour éviter les blocages sur le thread STA. La partie bloquante du TPL peut ne pas pomper les messages, provoquant un blocage.

Dans un scénario simplifié, le problème survient lorsque l'objet STA COM A en cours appelle l'objet B hors processus et s'attend à recevoir un rappel de B. L'appel à a.Method(b) ne revient jamais en raison d'une attente bloquante (ne pompant pas de messages) quelque part dans BlockingCollection .

La solution consiste à implémenter un contexte de synchronisation personnalisé qui pompe explicitement les messages à l'aide de CoWaitForMultipleHandles et à l'installer sur chaque thread STA démarré par StaTaskScheduler.

MsgWaitForMultipleObjectsEx est mieux adapté au pompage de messages que CoWaitForMultipleHandles. La méthode Wait d’un contexte de synchronisation personnalisé peut être implémentée en tant que redirecteur vers SynchronizationContext.WaitHelper ou contenir une boucle de pompage de messages entièrement fonctionnelle.

Le code suivant illustre une implémentation de contexte de synchronisation personnalisée qui inclut une boucle de pompage de messages :

<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>

L'utilisation de ce contexte de synchronisation personnalisé et de cette boucle de pompage de messages garantit que les messages sont pompés même lors de l'utilisation d'attentes de blocage sur le thread STA et empêche le blocage du thread STA.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn