Seguridad en hilos

(Redirigido desde «Thread-Safety»)

La seguridad en hilos es un concepto de programación aplicable en el contexto de los programas multihilos. Una pieza de código es segura en cuanto a los hilos si funciona correctamente durante la ejecución simultánea de múltiples hilos. En particular, debe satisfacer la necesidad de que múltiples hilos accedan a los mismos datos compartidos, y la necesidad de que una pieza compartida de datos sea accedida por solo un hilo en un momento dado.

La seguridad en hilos es un desafío clave en la programación multihilos. Antes solo concernía al programador del sistema operativo pero desde los últimos 1990s ha llegado a ser un asunto común. En un programa multihilos, varios threads se ejecutan simultáneamente en un espacio de direcciones compartido. Cada hilo tiene acceso a virtualmente toda la memoria de cada uno de los otros threads. Así el flujo de control y la secuencia de los accesos a datos a menudo tienen poca relación de lo que sería razonable esperar mirando el texto del programa. Thread-safety es una propiedad necesaria para minimizar el comportamiento inesperado restableciendo algunas de las correspondencias entre el flujo de control actual y el texto del programa.

Determinando la seguridad del hilo

editar

No es fácil determinar si una pieza de código es segura en cuanto a los hilos o no. Sin embargo, hay varios indicadores que sugieren la necesidad de un examen cuidadoso para determinar si es inseguro:

  • acceder a las variables globales o al heap
  • asignar/liberar recursos que tienen límites globales (ficheros, procesos y subprocesos, etc.)
  • accesos indirectos a través de handle o punteros
  • cualquier efecto co-lateral visible (por ejemplo, acceso a variables volátiles en el lenguaje de programación C)

Una subrutina tiene seguridad en hilos, y por tanto es reentrante, si solo usa variables de la pila, depende solo de los argumentos que le pasen, y solo llama a otras subrutinas con propiedades similares. A esto a veces se le llama "función pura" y se parece mucho a una función matemática. No todas las funciones reentrantes son thread-safe.

Consiguiendo la seguridad del hilo

editar

Hay unas pocas maneras de conseguir esta seguridad:

  • Código reentrante: Básicamente, escribir código de tal manera que pueda ser interrumpido durante una tarea, ser ejecutado (reentrado) de nuevo para realizar otra tarea, y después continuar con su tarea original. Esto normalmente incluye guardar la información de estado en variables locales, en lugar de usar variables estáticas o variables globales.
  • Exclusión mutua: El acceso a los datos compartidos es serializado usando mecanismos que aseguran que solo un thread está accediendo a los datos compartidos al mismo tiempo. Se requiere gran cautela si una pieza de código accede a múltiples piezas compartidas de datos - los problemas incluyen condición de carrera, deadlocks, livelocks, inanición de recursos (starvation), y otros males enumerados en los libros de texto de los sistemas operativos.
  • Almacenamiento thread-local: Variables están localizadas de manera que cada thread tiene su propia copia privada. Las variables retienen sus valores a través de la subrutina y otros límites de código, y el código al cual acceden podría no ser reentrante, pero dado que son locales a cada hilo, son thread-safe.
  • Operación atómica: Los datos compartidos son accedidos usando Atomicidad la cual no puede ser interrumpida por otros threads. Esto normalmente necesita usar instrucciones especiales del lenguaje máquina, las cuales podrían estar disponibles en una biblioteca de runtime. Dado que las operaciones son atómicas, los datos compartidos están siempre guardados en un estado válido, sin importar el orden en que los threads acceden. Atomicidad forma la base de muchos mecanismos de bloqueo de thread.

Un idioma de uso general combina estos acercamientos:

  • hacer cambios a una copia privada de los datos compartidos y entonces actualizad atómicamente los datos compartidos desde la copia privada. Así, la mayoría del código es concurrente, y se pierde poco tiempo en la serialización.

Véase también

editar

Enlaces externos

editar