2009-10-12 29 views
6

He utilizado la cola genérica en la colección C# y todos dicen que es mejor usar el objeto de System.Collection.Generic.Queue debido a la seguridad de los hilos.¿Qué significa el objeto 'thread safe'?

¿Desea asesorar sobre la decisión correcta de utilizar el objeto Queue y cómo es seguro para la ejecución de subprocesos?

Respuesta

5

Un tipo que es seguro para subprocesos se puede acceder de forma segura desde varios subprocesos sin preocuparse por la simultaneidad. Esto generalmente significa que el tipo es de solo lectura.

Curiosamente, Queue<T> es no seguro para hilos - que puede soportar lecturas simultáneas, siempre y cuando la cola no se modifica, pero eso no es lo mismo que la seguridad de los subprocesos.

Para pensar en la seguridad de los hilos, considere lo que sucedería si dos hilos estuvieran accediendo a un Queue<T> y apareciera un tercer hilo que comenzara a agregarse o eliminarse de este Queue<T>. Como este tipo no restringe este comportamiento, no es seguro para subprocesos.

25

"Thread safe" es un término un tanto desafortunado porque realmente no tiene una definición sólida. Básicamente significa que se garantiza que ciertas operaciones en el objeto se comportarán con sensatez cuando el objeto se está operando a través de múltiples hilos.

Considere el ejemplo más simple: un contador. Supongamos que tiene dos hilos que incrementan un contador. Si la secuencia de eventos va:

  • Enhebrar una lectura del contador, obtiene cero.
  • Enhebrar dos lecturas del contador, obtiene cero.
  • Subproceso uno incrementa cero, escribe uno para contrarrestar.
  • Rosque dos incrementos cero, escribe uno para contrarrestar.

Luego observe cómo el contador ha "perdido" uno de los incrementos. Las operaciones simples de incremento en los contadores no son seguras en cuanto a los hilos; para hacerlos seguras en hilos puedes usar bloqueos, o InterlockedIncrement.

De forma similar con las colas. Las colas que no son seguras para hilos no pueden "enganchar" en cola de la misma forma que los contadores que no son aptos para usar hilos pueden perder incrementos. Peor aún, las colas que no son seguras pueden incluso colapsar o producir resultados extravagantes si las usa en un escenario de subprocesos múltiples de forma incorrecta.

La dificultad con "hilo seguro" es que no está claramente definido. ¿Simplemente significa "no se bloqueará"? ¿Significa que se producirán resultados razonables? Por ejemplo, supongamos que tiene una colección "threadsafe". Es este código correcto?

if (!collection.IsEmpty) Console.WriteLine(collection[0]); 

No. Incluso si la colección es "multi-hilo", que no significa que este código es correcto; otro hilo podría haber hecho que la colección esté vacía después de la verificación, pero antes de la línea de escritura y, por lo tanto, este código podría colapsar, incluso si el objeto supuestamente es "seguro para hilos". De hecho, determinar que todas las combinaciones relevantes de las operaciones es seguro para la rosca es un problema extremadamente difícil.

Ahora, para llegar a su situación real: cualquier persona que le diga "debe usar la clase Queue, es mejor porque es segura", probablemente no tenga una idea clara de lo que están hablando. En primer lugar, Queue no es inseguro. En segundo lugar, si Queue es seguro o no es completamente irrelevante si solo está utilizando el objeto en un único hilo. Si tiene una colección a la que se accederá en varios subprocesos, entonces, como indiqué en mi ejemplo anterior, tiene un problema extremadamente difícil de resolver, independientemente de si la colección en sí es "en hilo". Debe determinar que cada combinación de operaciones que realice en la colección también es seguro para la tarea. Este es un problema muy difícil, y si es uno que enfrenta, entonces debe utilizar los servicios de un experto en este tema difícil.

+5

+1 Para el sólido testimonio de un experto. También tiene razón al señalar que "hilo seguro" es un concepto bastante difuso. –

+1

Me gusta cómo cada pregunta relacionada con la seguridad del hilo es respondida por el mismo tipo, del que he estado leyendo durante aproximadamente 2 horas. –

1

En el tratamiento de subprocesos múltiples, generalmente tiene que lidiar con problemas de simultaneidad. El término "problemas de concurrencia" se refiere a problemas que se introducen específicamente por la posibilidad de instrucciones de intercalación de dos contextos de ejecución diferentes en un recurso compartido por ambos. Aquí, en términos de seguridad de subprocesos, los contextos de ejecución son dos subprocesos dentro de un proceso; Sin embargo, en temas relacionados, podrían ser procesos.

Las medidas de seguridad del hilo se ponen en marcha para lograr dos objetivos principalmente. Primero es recuperar el determinismo con respecto a lo que sucede si el cambio de contexto de subprocesos (que de otro modo es controlado por el SO y básicamente no determinista en programas de nivel de usuario), para evitar que ciertas tareas se terminen a la mitad o que dos contextos escriban el mismo lugar en la memoria uno después del otro. La mayoría de las medidas simplemente usan un poco de instrucciones test-and-set soportadas por hardware y similares, así como el nivel de software synchronization constructs para forzar a todos los demás contextos de ejecución a mantenerse alejados de un tipo de datos mientras que otro está haciendo un trabajo que no debe interrumpirse.

Normalmente, los objetos que son de solo lectura son seguros para subprocesos. Muchos objetos que no son de solo lectura pueden tener acceso a datos (de solo lectura) con múltiples hilos sin problema, si el objeto no se modifica en el medio. Pero esto no es seguridad de hilo. La seguridad del subproceso es cuando se realizan todo tipo de operaciones con un tipo de datos para evitar que cualquier modificación de un subproceso provoque daños en los datos o interbloqueo incluso cuando se trata de muchas lecturas y escrituras concurrentes.