Question

J'ai hérité d'un peu de code threadé, et après l'avoir examiné, je trouve des structures comme celle-ci (dans une méthode de thread d'arrière-plan):

private ManualResetEvent stopEvent = new ManualResetEvent(false);

private void Run_Thread() {
    while (!stopEvent.WaitOne(0, true)) {
        // code here
    }
}

En général, il existe une méthode Stop() publique ou privée, comme ceci:

public void Stop() {
    stopEvent.Set();
    bgThread.Join();
}

Ma question est la suivante: à quoi sert l'utilisation d'une poignée d'attente ici?Il semble que cela soit fait pour s'assurer que la signalisation d'un arrêt est une opération atomique, mais je pensais que l'écriture dans un booléen était de toute façon atomique.Si tel est le cas, y a-t-il une raison de ne pas simplement utiliser ce qui suit:

private void Run_Thread() {
    while(!stop) {
        // code here
    }
}

public void Stop() { 
    stop = true;
    bgThread.Join();
}
Était-ce utile?

La solution

Ecrire dans une variable bool est en effet atomique, mais à moins que la variable ne soit également volatile (ou que vous introduisiez une autre synchronisation), elle pourrait ne pas être visible à partir d'autres threads.De tels problèmes peuvent être difficiles à localiser et à reproduire.

Par exemple, sur mon ordinateur portable x64, le programme suivant s'arrête correctement.Sur mon netbook x86, il se bloque pour toujours.(Tous deux compilés avec csc /o+ Test.cs).

using System;
using System.Threading;

class Test
{
    static bool stop = false;

    static void Main(string[] args)
    {
        new Thread(CountLots).Start();
        Thread.Sleep(100);
        stop = true;
        Console.WriteLine("Finished...");
    }    

    static void CountLots()
    {
        long total = 0;
        while (!stop)
        {
            total++;
        }
    }
}

Dans ce cas particulier, il semble raisonnable d'utiliser un indicateur volatile - bien que si vous utilisez .NET 4, il serait préférable d'utiliser les mécanismes d'annulation de tâche :)

Bien sûr, normalement, une meilleure raison d'utiliser autre chose qu'un drapeau est si vous voulez attendre une condition - que ce soit "y a-t-il un nouvel élément" ou "ai-je été annulé" (ou les deux) - sans serrer-en boucle.

Autres conseils

Vous ne pouvez pas faire une "attente" contrôlée / bloquante sur un booléen (bien que vous n'en ayez probablement pas besoin, et Monitor pourrait être plus léger de toute façon).

En tant que flag , un booléen d'annulation est très bien, mais vous voudrez peut-être rendre le booléen volatil pour éviter que le cache du registre ne soit un problème.

Le simple fait d'utiliser un booléen ne fonctionnera pas, vous devez le déclarer volatile pour dire au générateur de code qu'il ne doit pas stocker la valeur dans un registre CPU.L'heure exacte à laquelle le thread verra la valeur définie sur true est imprévisible, elle dépend fortement du type de processeur sur lequel votre code s'exécute.

Détails laids, ceux que vous pouvez ignorer lorsque vous utilisez un WaitHandle.

Le dernier argument doit être False btw.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top