Pregunta

He heredado un poco de código roscado, y al revisarlo, estoy encontrando estructuras como esta (dentro de un método de subproceso de fondo):

private ManualResetEvent stopEvent = new ManualResetEvent(false);

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

Por lo general, hay un público o privado Stop() Método, como así:

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

Mi pregunta es esta: ¿qué se sirve usando un mango de espera aquí? Parece que esto se hace para garantizar que la señalización para una parada sea una operación atómica, pero pensé que escribir para un booleano era atómico de todos modos. Si ese es el caso, ¿hay alguna razón para no usar lo siguiente:

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

public void Stop() { 
    stop = true;
    bgThread.Join();
}
¿Fue útil?

Solución

Escribiendo a un bool La variable es de hecho atómica, pero a menos que la variable también sea volátil (O introduce alguna otra sincronización), entonces podría no ser visible desde otros hilos. Tales problemas pueden ser difíciles de rastrear y reproducir.

Por ejemplo, en mi computadora portátil X64, el siguiente programa se detiene correctamente. En mi netbook x86, cuelga para siempre. (Ambos compilados 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++;
        }
    }
}

En este caso particular, parece razonable usar un indicador volátil, aunque si está usando .NET 4, sería mejor usar los mecanismos de cancelación de tareas :)

Por supuesto, normalmente una mejor razón para usar algo más que una bandera es si desea esperar alguna condición, ya sea que sea "hay un artículo nuevo" o "me han cancelado" (o ambos), sin bucles apretados.

Otros consejos

No puede hacer un "esperar" controlado / bloqueo en un bool (aunque probablemente no lo necesite, y el monitor podría ser más ligero de todos modos).

Como cancelación bandera Bool está bien, pero es posible que desee hacer que el Bool sea volátil para evitar que el caché de registros sea un problema.

Solo usar un bool no funcionará, debes declararlo volátil Para decirle al generador de código que no debe almacenar el valor en un registro de CPU. El momento exacto en que el hilo verá que el valor establecido en verdadero es impredecible, depende en gran medida del tipo de CPU en la que se ejecute su código.

Detalles feos, los que puedes ignorar cuando usas un WaitHandle.

El último argumento debe ser falso por cierto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top