¿Qué se entiende por código" thread-safe"?


¿Significa que dos subprocesos no pueden cambiar los datos subyacentes simultáneamente? ¿O significa que el segmento de código dado se ejecutará con resultados predecibles cuando más de un subproceso lo esté ejecutando?

Author: darth_coder, 2008-11-04

15 answers

De wikipedia:

Thread safety es un concepto de programación de computadoras aplicable en el contexto de programas multihilo. Un fragmento de código es seguro para subprocesos si funciona correctamente durante la ejecución simultánea por múltiples subprocesos. En particular, debe satisfacer la necesidad de que varios subprocesos accedan a los mismos datos compartidos, y la necesidad de que solo un subproceso pueda acceder a un fragmento de datos compartido en un momento dado.

...

Hay algunas maneras de lograr la seguridad del hilo:

Reentrancy

Escribir código de tal manera que pueda ser ejecutado parcialmente por una tarea, reingresado por otra tarea, y luego reanudado de la tarea original. Esto requiere guardar la información de estado en variables locales a cada tarea, generalmente en su pila, en lugar de en variables estáticas o globales.

Exclusión Mutua

El acceso a los datos compartidos se serializa utilizando mecanismos que garantizan un hilo lee o escribe los datos compartidos en cualquier momento. Se requiere un gran cuidado si una pieza de código accede a múltiples piezas compartidas de datos: los problemas incluyen condiciones de carrera, bloqueos, bloqueos de vida, inanición y varios otros males enumerados en muchos libros de texto de sistemas operativos.

Thread-almacenamiento local

Las variables se localizan para que cada hilo tenga su propia copia privada. Estas variables conservan sus valores a través de subrutinas y otros límites de código, y son seguros para subprocesos, ya que son locales para cada subproceso, a pesar de que el código que accede a ellos podría ser reentrante.

Operaciones Atómicas

Se accede a los datos compartidos mediante operaciones atómicas que no pueden ser interrumpidas por otros subprocesos. Esto generalmente requiere el uso de instrucciones especiales de lenguaje de máquina, que pueden estar disponibles en una biblioteca de tiempo de ejecución. Dado que las operaciones son atómicas, los datos compartidos siempre se mantienen en un estado válido, sin importar qué otros los hilos acceden a él. Las operaciones atómicas forman la base de muchos mecanismos de bloqueo de rosca.

Leer más :

Http://en.wikipedia.org/wiki/Thread_safety


 205
Author: Blauohr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-04 14:29:56

El código Thread-safe es un código que funcionará incluso si muchos Threads lo están ejecutando simultáneamente.

Http://mindprod.com/jgloss/threadsafe.html

 68
Author: Marek Blotny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-04 12:17:28

Una pregunta más informativa es qué hace que el código no sea seguro para el hilo, y la respuesta es que hay cuatro condiciones que deben ser ciertas... Imagine el siguiente código (y es traducción en lenguaje automático)

totalRequests = totalRequests + 1
MOV EAX, [totalRequests]   // load memory for tot Requests into register
INC EAX                    // update register
MOV [totalRequests], EAX   // store updated value back to memory
  1. La primera condición es que haya ubicaciones de memoria a las que se pueda acceder desde más de un hilo. Normalmente, estas ubicaciones son variables globales/estáticas o son memoria de montón accesible desde variables globales/estáticas. Cada hilo obtiene su propio marco de pila para variables locales con ámbito de función / método, por lo que estas variables de función/método locales, otoh, (que están en la pila) son accesibles solo desde el subproceso que posee esa pila.
  2. La segunda condición es que hay una propiedad (a menudo llamada invariante ), que está asociada con estas ubicaciones de memoria compartida, que debe ser verdadera, o válida, para que el programa funcione correctamente. En el ejemplo anterior, la propiedad es que " totalRequests debe representar con precisión el total número de veces que cualquier subproceso ha ejecutado cualquier parte de la instrucción increment". Por lo general, esta propiedad invariante debe mantenerse verdadera (en este caso, totalRequests debe mantener un conteo exacto) antes de que se produzca una actualización para que la actualización sea correcta.
  3. La tercera condición es que la propiedad invariante NO se mantenga durante alguna parte de la actualización real. (Es temporalmente inválido o falso durante alguna parte del procesamiento). En este caso particular, desde el momento totalRequests es si se obtiene hasta el momento en que se almacena el valor actualizado, totalRequests no satisface el invariante.
  4. La cuarta y última condición que debe ocurrir para que ocurra una raza (y para que el códigoNO ser "seguro para el hilo") es que otro hilo debe ser capaz de acceder a la memoria compartida mientras el invariante está roto, causando así un comportamiento inconsistente o incorrecto.
 42
Author: Charles Bretana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-05 14:55:06

Me gusta la definición de Java Concurrency de Brian Goetz en la práctica por su exhaustividad

"Una clase es segura para subprocesos si se comporta correctamente cuando se accede desde múltiples subprocesos, independientemente de la programación o intercalación de la ejecución de esos subprocesos por el entorno de tiempo de ejecución, y sin sincronización adicional u otra coordinación por parte del código de llamada."

 32
Author: Buu Nguyen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-04 14:32:11

Thread-safe-code funciona como se especifica, incluso cuando se introduce simultáneamente por diferentes hilos. Esto a menudo significa que las estructuras de datos internas u operaciones que deben ejecutarse sin interrupciones están protegidas contra diferentes modificaciones al mismo tiempo.

 22
Author: Mnementh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-15 10:43:50

Como otros han señalado, la seguridad de subprocesos significa que una pieza de código funcionará sin errores si es utilizada por más de un subproceso a la vez.

Vale la pena ser consciente de que esto a veces tiene un costo, de tiempo de computadora y codificación más compleja, por lo que no siempre es deseable. Si una clase se puede usar de forma segura en un solo hilo, puede ser mejor hacerlo.

Por ejemplo, Java tiene dos clases que son casi equivalentes, StringBuffer y StringBuilder. La diferencia es que StringBuffer es thread-safe, por lo que una sola instancia de un StringBuffer puede ser utilizada por varios subprocesos a la vez. StringBuilder no es seguro para subprocesos, y está diseñado como un reemplazo de mayor rendimiento para aquellos casos (la gran mayoría) cuando la cadena está construida por un solo subproceso.

 22
Author: Marcus Downing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-28 13:39:51

Una forma más fácil de entenderlo, es lo que hace que el código no sea seguro para subprocesos. Hay dos problemas principales que harán que una aplicación enhebrada tenga un comportamiento no deseado.

  • Acceso a variable compartida sin bloqueo
    Esta variable podría ser modificada por otro hilo mientras se ejecuta la función. Desea prevenirlo con un mecanismo de bloqueo para estar seguro del comportamiento de su función. La regla general es mantener la cerradura durante el menor tiempo posible posible.

  • Punto muerto causado por la dependencia mutua de la variable compartida
    Si tiene dos variables compartidas A y B. En una función, primero bloquea A y luego bloquea B. En otra función, comienza a bloquear B y después de un tiempo, bloquea A. Este es un bloqueo potencial donde la primera función esperará a que B se desbloquee cuando la segunda función esperará a que A se desbloquee. Este problema probablemente no ocurrirá en su entorno de desarrollo y solo de vez en cuando. A evítalo, todas las cerraduras deben estar siempre en el mismo orden.

 16
Author: Hapkido,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-15 07:42:09

Sí y no.

La seguridad de subprocesos es un poco más que asegurarse de que solo se accede a sus datos compartidos por un subproceso a la vez. Hay que garantizar el acceso secuencial a los datos compartidos, evitando al mismo tiempo condiciones de carrera, puntos muertos, livelocks , y hambre de recursos.

Los resultados impredecibles cuando se ejecutan múltiples subprocesos son no una condición requerida del código seguro para subprocesos, pero a menudo es un subproducto. Para por ejemplo, podría tener un esquema productor-consumidor configurado con una cola compartida, un subproceso productor y pocos subprocesos de consumo, y el flujo de datos podría ser perfectamente predecible. Si empiezas a introducir más consumidores, verás más resultados aleatorios.

 9
Author: Bill the Lizard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-04 12:59:36

En esencia, muchas cosas pueden salir mal en un entorno de subprocesos múltiples (reordenamiento de instrucciones, objetos parcialmente construidos, misma variable que tiene diferentes valores en diferentes subprocesos debido al almacenamiento en caché a nivel de CPU, etc.).

Me gusta la definición dada por Java Concurrency in Practice :

Una [porción de código] es segura para subprocesos si se comporta correctamente cuando se accede desde múltiples subprocesos, independientemente de la programación o intercalación de la ejecución de esos hilos por el entorno de tiempo de ejecución, y sin sincronización adicional u otra coordinación por parte del código de llamada.

Por correctamente significan que el programa se comporta de acuerdo con sus especificaciones.

Ejemplo artificial

Imagina que implementas un contador. Se podría decir que se comporta correctamente si:

  • counter.next() nunca devuelve un valor que ya haya sido devuelto antes (suponemos que no hay desbordamiento sucesivamente. para simplificar)
  • todos los valores desde 0 hasta el valor actual se han devuelto en algún momento (no se omite ningún valor)

Un contador seguro de subprocesos se comportaría de acuerdo con esas reglas independientemente de cuántos subprocesos accedan simultáneamente (lo que normalmente no sería el caso de una implementación ingenua).

Nota: publicación cruzada en Programadores

 8
Author: assylias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-12 07:31:21

Simply - code se ejecutará bien si muchos subprocesos están ejecutando este código al mismo tiempo.

 7
Author: Greg Balajewicz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-12 09:27:12

No confunda la seguridad del hilo con el determinismo. El código thread-safe también puede ser no determinista. Dada la dificultad de depurar problemas con código enhebrado, este es probablemente el caso normal. :-)

Thread safety simplemente garantiza que cuando un hilo está modificando o leyendo datos compartidos, ningún otro hilo puede acceder a él de una manera que cambie los datos. Si su código depende de un cierto orden de ejecución para la corrección, entonces necesita otros mecanismos de sincronización más allá de esos requerido para la seguridad del hilo para garantizar esto.

 3
Author: tvanfosson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-04 12:31:51

Para completar otras respuestas:

La sincronización es solo una preocupación cuando el código en su método hace una de dos cosas:

  1. funciona con algún recurso externo que no es seguro para subprocesos.
  2. Lee o cambia un objeto persistente o un campo de clase

Esto significa que las variables definidas DENTRO de su método son siempre threadsafe. Cada llamada a un método tiene su propia versión de estas variables. Si el método es llamado por otro hilo, o por el mismo hilo, o incluso si el método se llama a sí mismo (recursión), los valores de estas variables no se comparten.

Subproceso de programación no está garantizado a ser round-robin. Una tarea puede acaparar totalmente la CPU a expensas de hilos de la misma prioridad. Puedes usar Hilo.yield() tener una conciencia. Puede utilizar (en java) Hilo.setPriority (Thread.NORM_PRIORITY-1) para bajar la prioridad de un hilo

Además tenga cuidado con:

  • el gran costo de tiempo de ejecución (ya mencionado por otros) en aplicaciones que iteran sobre estas estructuras "seguras para subprocesos".
  • Hilo.sleep (5000) se supone que duerme durante 5 segundos. Sin embargo, si alguien cambia el tiempo del sistema, usted puede dormir durante mucho tiempo o ningún tiempo en absoluto. El sistema operativo registra el tiempo de activación en forma absoluta, no relativa.
 3
Author: VonC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-04 12:41:38

Me gustaría añadir algo más de información sobre otras buenas respuestas.

La seguridad de subprocesos implica que varios subprocesos pueden escribir / leer datos en el mismo objeto sin errores de inconsistencia de memoria. En el programa altamente multihilo, un programa seguro del hilo no causa efectos secundarios a los datos compartidos.

Echa un vistazo a esta pregunta SE para más detalles:

¿Qué significa threadsafe?

Garantía del programa Thread safe consistencia de la memoria.

De la página de documentación de oracle en API concurrente avanzada:

Propiedades de consistencia de Memoria:

El Capítulo 17 de la Especificación del Lenguaje Java™ define la relación sucede-antes en operaciones de memoria como lecturas y escrituras de variables compartidas. Los resultados de una escritura por un hilo están garantizados para ser visibles para una lectura por otro hilo solo si la operación de escritura ocurre-antes de la lectura operación.

Las construcciones synchronized y volatile, así como los métodos Thread.start() y Thread.join(), pueden formar sucede-antes de relaciones.

Los métodos de todas las clases en java.util.concurrent y sus subpaquetes extienden estas garantías a sincronización de nivel superior. En particular:

  1. Las acciones en un subproceso antes de colocar un objeto en cualquier colección concurrente ocurren-antes de las acciones posteriores al acceso o eliminación de ese elemento del colección en otro hilo.
  2. Las acciones en un hilo antes del envío de un Runnable a un Executor ocurren-antes de que comience su ejecución. Del mismo modo para los elementos llamados enviados a un ExecutorService.
  3. Las acciones tomadas por el cálculo asincrónico representado por un Future suceden-antes de las acciones posteriores a la recuperación del resultado a través de Future.get() en otro hilo.
  4. Acciones antes de" liberar " sincronizador métodos como Lock.unlock, Semaphore.release, and CountDownLatch.countDown suceder - antes de las acciones posteriores a una método de "adquisición" exitoso como Lock.lock, Semaphore.acquire, Condition.await, and CountDownLatch.await en el mismo objeto sincronizador en otro subproceso.
  5. Para cada par de subprocesos que intercambian objetos con éxito a través de un Exchanger, las acciones anteriores al exchange() en cada subproceso ocurren-antes de las posteriores al exchange() correspondiente en otro subproceso.
  6. Las acciones anteriores a llamar CyclicBarrier.await y Phaser.awaitAdvance (así como sus variantes) ocurren-antes de las acciones realizadas por la acción de barrera, y las acciones realizadas por la acción de barrera suceder - antes de las acciones posteriores a un retorno exitoso de la espera correspondiente en otros hilos.
 3
Author: Ravindra babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:32

Sí y sí. Implica que los datos no son modificados por más de un hilo simultáneamente. Sin embargo, su programa puede funcionar como se espera y parecer seguro para subprocesos, incluso si fundamentalmente no lo es.

Tenga en cuenta que la imprevisibilidad de los resultados es una consecuencia de las 'condiciones de carrera' que probablemente resulten en que los datos se modifiquen en un orden diferente al esperado.

 1
Author: Steve Knight,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-04 12:36:15

En palabras simples: P Si es seguro ejecutar múltiples subprocesos en un bloque de código, es seguro para subprocesos *

* se aplican condiciones

Las condiciones son mencionadas por otras respuestas como 1. El resultado debe ser el mismo si ejecuta un subproceso o varios subprocesos sobre él, etc.

 0
Author: shabby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-15 09:19:52