Domanda

Ho ereditato un po 'di codice thread e, dopo averlo esaminato, sto trovando strutture come questa (all'interno di un metodo del thread di sfondo):

private ManualResetEvent stopEvent = new ManualResetEvent(false);

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

Di solito c'è un pubblico o un privato Stop() Metodo, come così:

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

La mia domanda è questa: cosa viene servito usando un manico di attesa qui? Sembra che ciò venga fatto per garantire che la segnalazione di un arresto fosse un'operazione atomica, ma ho pensato che scrivere in un booleano fosse comunque atomico. In tal caso, c'è qualche motivo per non usare solo quanto segue:

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

public void Stop() { 
    stop = true;
    bgThread.Join();
}
È stato utile?

Soluzione

Scrivendo a a bool La variabile è effettivamente atomica, ma a meno che la variabile non sia anche volatile (o si introduce qualche altra sincronizzazione) Quindi potrebbe non essere visibile da altri thread. Tali problemi possono essere difficili da rintracciare e riprodurre.

Ad esempio, sul mio laptop X64, il seguente programma si interrompe correttamente. Sul mio netbook X86, è appeso per sempre. (Entrambi compilati con 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++;
        }
    }
}

In questo caso particolare, sembra ragionevole utilizzare un flag volatile, anche se se si utilizza .NET 4 sarebbe meglio utilizzare i meccanismi di cancellazione delle attività :)

Ovviamente normalmente una ragione migliore per usare qualcosa di diverso da una bandiera è se vuoi aspettare qualche condizione - che si tratti di "esiste un nuovo elemento" o "sono stato cancellato" (o entrambi) - senza lottare a senso stretto.

Altri suggerimenti

Non puoi fare un "attesa" controllato / bloccante su un bool (anche se probabilmente non è necessario, e il monitor potrebbe comunque essere più leggero).

Come annullamento bandiera Bool va bene, ma potresti voler rendere il bool volatile per evitare che la cache del registro sia un problema.

Solo usare un bool non funzionerà, devi dichiararlo volatile Per dire al generatore di codice che non dovrebbe archiviare il valore in un registro CPU. Il tempo esatto in cui il thread vedrà il valore impostato su true è imprevedibile, dipende fortemente dal tipo di CPU su cui è eseguito il codice.

Dettagli brutti, quelli che puoi ignorare quando usi un waithandle.

L'ultimo argomento dovrebbe essere falso btw.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top