terminado - ¿Es seguro usar una bandera booleana para detener la ejecución de un hilo en C#
subproceso en ejecución o terminado no se puede reiniciar (4)
Los booleanos son atómicos en C #, sin embargo, si desea modificarlo en un subproceso y leerlo en otro, deberá marcarlo como mínimo volátil. De lo contrario, el hilo de lectura solo puede leerlo una vez en un registro.
Mi principal preocupación es con la bandera booleana ... ¿es seguro usarla sin ninguna sincronización? He leído en varios lugares que es atómico (incluida la documentación).
class MyTask
{
private ManualResetEvent startSignal;
private CountDownLatch latch;
private bool running;
MyTask(CountDownLatch latch)
{
running = false;
this.latch = latch;
startSignal = new ManualResetEvent(false);
}
// A method which runs in a thread
public void Run()
{
startSignal.WaitOne();
while(running)
{
startSignal.WaitOne();
//... some code
}
latch.Signal();
}
public void Stop()
{
running = false;
startSignal.Set();
}
public void Start()
{
running = true;
startSignal.Set();
}
public void Pause()
{
startSignal.Reset();
}
public void Resume()
{
startSignal.Set();
}
}
¿Es esta una forma segura de diseñar una tarea de esta manera? ¿Alguna sugerencia, mejoras, comentarios?
Nota: Escribí mi clase personalizada CountDownLatch
en caso de que se esté preguntando de dónde lo estoy obteniendo.
Actualizar:
Aquí está mi CountDownLatch también:
public class CountDownLatch
{
private volatile int m_remain;
private EventWaitHandle m_event;
public CountDownLatch (int count)
{
if (count < 0)
throw new ArgumentOutOfRangeException();
m_remain = count;
m_event = new ManualResetEvent(false);
if (m_remain == 0)
{
m_event.Set();
}
}
public void Signal()
{
// The last thread to signal also sets the event.
if (Interlocked.Decrement(ref m_remain) == 0)
m_event.Set();
}
public void Wait()
{
m_event.WaitOne();
}
}
Los booleanos son atómicos en C #: http://msdn.microsoft.com/en-us/library/aa691278(VS.71).aspx
Más vale que lo volatile
:
La palabra clave volátil indica que un campo puede ser modificado por múltiples subprocesos de ejecución simultáneos. Los campos que se declaran volátiles no están sujetos a las optimizaciones del compilador que asumen el acceso por un único hilo. Esto asegura que el valor más actualizado esté presente en el campo en todo momento.
Pero cambiaría tu ciclo:
startSignal.WaitOne();
while(running)
{
//... some code
startSignal.WaitOne();
}
Como está en su publicación, el ''cierto código'' podría ejecutarse cuando se detiene el subproceso (es decir, cuando se llama a Stop), que es inesperado e incluso puede ser incorrecto.
Por cierto, acabo de notar esta parte del código:
// A method which runs in a thread
public void Run()
{
startSignal.WaitOne();
while(running)
{
startSignal.WaitOne();
//... some code
}
latch.Signal();
}
Necesitarás desbloquear el hilo del trabajador dos veces usando "startSignal.Set ()" para el código dentro del bloque while para ejecutar.
¿Esto es deliberado?