thread squad que lock for espaƱol black c# multithreading synchronization

c# - squad - Queue<T>.Dequeue returns null



thread sync black squad (7)

Tengo un escenario donde

  • varios hilos están presionando datos en una Cola

  • solo UN hilo está procesando datos usando el código a continuación

código -

while ( Continue ) { while ( queue.Count > 0 ) { MyObj o = queue.Dequeue(); someProcess(o); } myAutoResetEvent.WaitOne(); }

Pero a veces, queue.Dequeue () devuelve null en el escenario anterior ¿Qué ofrece?


Asegúrese de que nada esté introduciendo valores null en la cola. null s están permitidos como valores en cola. Además, de acuerdo con este documento , solo los miembros estáticos de Queue<T> son seguros para la ejecución de subprocesos, así que ten cuidado de leer y escribir entre subprocesos.


Guffa está en lo cierto, tener múltiples hilos leyendo y escribiendo en la cola causará problemas, porque Queue <T> no es seguro para subprocesos.

Si está utilizando .NET 4, use la clase ConcurrentQueue <T> , que es segura para subprocesos. Si no estás en .NET 3 o anterior, puedes hacer tu propio bloqueo, como señaló Guffa, o utilizar una biblioteca de terceros.


Necesita sincronizar el acceso a la cola. Coloque instrucciones de lock alrededor de todas las secciones de código que acceden a la cola (tanto de lectura como de escritura). Si accede a la cola simultáneamente desde múltiples hilos, las estructuras internas pueden estar dañadas y casi cualquier cosa puede suceder.


Necesitas leer esta publicación en el blog .

Además, aquí hay un esqueleto muy mínimo de un "canal" para la comunicación entre hilos:

public class Channel<T> { private readonly Queue<T> _queue = new Queue<T>(); public void Enqueue(T item) { lock (_queue) { _queue.Enqueue(item); if (_queue.Count == 1) Monitor.PulseAll(_queue); } } public T Dequeue() { lock (_queue) { while (_queue.Count == 0) Monitor.Wait(_queue); return _queue.Dequeue(); } } }


Tu dices:

varios hilos están presionando datos en una Cola

El método Queue<T>.Enqueue no es seguro para subprocesos. Esto significa que el trabajo se realiza dentro del método Enqueue que debe sincronizarse si lo están llamando múltiples hilos. Un ejemplo simple sería actualizar la propiedad Count . Es una apuesta segura que en algún lugar del método Enqueue hay una línea que se ve así:

++count;

Pero como todos sabemos, esta no es una operación atómica. Realmente es más así (en términos de lo que está sucediendo realmente):

int newCount = count + 1; count = newCount;

Así que supongamos que el count actualmente es 5 y el subproceso 1 pasa int newCount = count + 1 ... luego el subproceso 1 piensa: "OK, el recuento ahora es 5, así que lo haré 6." Pero la próxima operación que se ejecuta es donde el hilo 2 llega a int newCount = count + 1 y piensa lo mismo que el hilo 1 ("el recuento ahora es 6"). Entonces, se agregaron dos elementos a la cola, pero el conteo solo pasó de 5 a 6.

Este es solo un ejemplo muy básico de cómo un método que no es seguro para subprocesos como Queue<T>.Enqueue puede Queue<T>.Enqueue cuando el acceso no está sincronizado. No explica específicamente lo que está sucediendo en su pregunta; mi intención es simplemente señalar que lo que estás haciendo no es seguro para subprocesos y provocará un comportamiento inesperado .


¿Por qué no resuelves el problema de esa manera?

while (IsRunning) { do { MyObj myObj = queue.Dequeue(); if (myObj != null) { DoSomethingWith(myObj); } } while (myObj != null); myAutoResetEvent.WaitOne(); }

Actualizar

Ok, después de leer el comentario de Earwickers y todas las demás respuestas, estás bien y solo soy falso. Por lo tanto , no use el código anterior en contextos de subprocesos múltiples .


Si está utilizando una cola no genérica (no es que yo recomiende usarla), puede usar el método Queue.Synchronized para obtener un contenedor seguro para subprocesos:

Queue queue = Queue.Synchronized(new Queue());

De lo contrario, debería encargarse de encerrarse, como sugieren otros.