Spinlock
![]() | El texto que sigue es una traducción defectuosa. Si quieres colaborar con Wikipedia, busca el artículo original y mejora esta traducción. Copia y pega el siguiente código en la página de discusión del autor de este artículo: {{subst:Aviso mal traducido|Spinlock}} ~~~~ |
En ingeniería de software , un spinlock es un bloqueo que hace que un hilo que intenta adquirirlo simplemente espere en un bucle ("girar" en inglés "spin") mientras comprueba repetidamente si el bloqueo(lock) está disponible. Como el hilo permanece activo pero no está realizando una tarea útil, el uso de dicho bloqueo es una especie de espera ocupada . Una vez adquiridos, los spinlocks generalmente se mantendrán hasta que se liberen explícitamente, aunque en algunas implementaciones se pueden liberar automáticamente si el hilo que está esperando en (lo que contiene el bloqueo) bloquea, o "se va a dormir".
Debido a que evitan la sobrecarga de la reprogramación de procesos del sistema operativo o el cambio de contexto , los spinlocks son eficientes si es probable que los hilos se bloqueen solo por períodos cortos. Por esta razón, los kernels del sistema operativo a menudo usan spinlocks. Sin embargo, los spinlocks se vuelven un desperdicio si se mantienen durante más tiempo, ya que pueden evitar que otros hilos se ejecuten y requieren reprogramación. Cuanto más tiempo un hilo mantiene un bloqueo, mayor es el riesgo de que el programador(scheduler) del sistema operativo interrumpa el hilo mientras mantiene el bloqueo. Si esto sucede, otros hilos se dejarán "girando" (tratando repetidamente de adquirir el candado), mientras que el hilo que sujeta el candado no está avanzando hacia su liberación. El resultado es un aplazamiento indefinido hasta que el hilo que sujeta la cerradura pueda terminar y soltarlo. Esto es especialmente cierto en un sistema de procesador único, donde cada subproceso en espera de la misma prioridad puede desperdiciar su cantidad (tiempo asignado en que se puede ejecutar un subproceso) girando hasta que el subproceso que contiene el bloqueo finalice finalmente.
Implementar bloqueos de giro correctamente ofrece desafíos porque los programadores deben tener en cuenta la posibilidad de acceso simultáneo a la cerradura, lo que podría causar condiciones de carrera . En general, dicha implementación solo es posible con instrucciones especiales en lenguaje de ensamblaje, como operaciones atómicas de prueba y configuración , y no se puede implementar fácilmente en lenguajes de programación que no admitan operaciones verdaderamente atómicas. [1] En arquitecturas sin tales operaciones, o si se requiere la implementación de lenguaje de alto nivel, se puede usar un algoritmo de bloqueo no atómico, por ejemplo, el algoritmo de Peterson . Sin embargo, tal implementación puede requerir más memoria que un spinlock, ser más lenta para permitir el progreso después del desbloqueo, y puede no ser implementable en un lenguaje de alto nivel si se permite la ejecución fuera de orden .
Implementación de ejemplo
El siguiente ejemplo usa el lenguaje de ensamblaje x86 para implementar un spinlock. Funcionará en cualquier procesador compatible con Intel 80386.
; Sintaxis de Intel locked: ; La variable de bloqueo. 1 = bloqueado, 0 = desbloqueado. dd 0 spin_lock: mov eax, 1 ; Establece el registro EAX a 1. xchg eax, [locked] ; Cambia automáticamente el registro EAX ; con la variable de bloqueo. ; Esto siempre va a guardar 1 en el bloqueo, ; dejando el valor previo en el registro EAX. test eax, eax ; Prueba el EAX consigo mismo. Entre otras cosas, esto va ; a establecer el Indicador Cero del procesador si EAX es 0. ; Si EAX es 0, entonces el bloqueo estaba desbloqueado y ; lo acabamos de desbloquear. ; En caso contrario, EAX es 1 y no adquirimos el bloqueo. jnz spin_lock ; Salta hacia la instrucción MOV si el Indicador Cero no está ; establecido; el bloqueo estaba bloqueado anteriormente, ; entonces debemos girar en círculos (spin) hasta que se desbloquee. ret ; El bloqueo fue adquirido, se vuelve a la función que llamó ; al spinlock. spin_unlock: xor eax, eax ; Se establece el registro EAX a 0. xchg eax, [locked] ; Se cambia automáticamente el registro ; EAX con la variable de bloqueo. ret ; el bloqueo fue liberado.
Optimizaciones significativas
La implementación simple anterior funciona en todas las CPU que usan la arquitectura x86. Sin embargo, varias optimizaciones de rendimiento son posibles:
En las implementaciones posteriores de la arquitectura x86, spin_unlock puede usar de forma segura un MOV desbloqueado en lugar del XCHG bloqueado más lento. Esto se debe a sutiles reglas de ordenación de memoria que lo respaldan, aunque MOV no es una barrera de memoria completa. Sin embargo, algunos procesadores (algunos procesadores Cyrix , algunas revisiones de Intel Pentium Pro (debido a errores) y sistemas Pentium e i486 SMP anteriores) harán lo incorrecto y los datos protegidos por el bloqueo podrían dañarse. En la mayoría de las arquitecturas que no son x86, se debe utilizar una barrera de memoria explícita o instrucciones atómicas (como en el ejemplo). En algunos sistemas, como IA-64 , hay instrucciones especiales de "desbloqueo" que proporcionan la ordenación de memoria necesaria.
Para reducir el tráfico de bus entre CPU, el código que intenta adquirir un bloqueo debe leer en bucle sin intentar escribir nada hasta que lea un valor cambiado. Debido a los protocolos de caché MESI , esto hace que la línea de caché para el bloqueo se convierta en "Compartida"; entonces, notablemente, no hay tráfico en el bus mientras una CPU espera el bloqueo. Esta optimización es efectiva en todas las arquitecturas de CPU que tienen un caché por CPU, porque MESI está muy extendida.
Alternativas
La implementación simple anterior funciona en todas las CPU que usan la arquitectura x86. Sin embargo, varias optimizaciones de rendimiento son posibles:
No adquieras el candado En muchas situaciones, es posible diseñar estructuras de datos que no requieren bloqueo , por ejemplo, mediante el uso de datos por subproceso o por CPU y la desactivación de interrupciones.- Cambie a un hilo diferente mientras espera. Esto normalmente implica unir el hilo actual a una cola de hilos esperando el bloqueo, seguido de cambiar a otro hilo que está listo para hacer un trabajo útil. Este esquema también tiene la ventaja de que garantiza que la falta de recursos no ocurra siempre que todos los hilos abandonen los bloqueos que adquieren y se pueden tomar decisiones sobre qué hilo debe avanzar primero. Los spinlocks que nunca implican conmutación, utilizables por sistemas operativos en tiempo real , a veces se llaman spinlocks sin formato . [2]
La mayoría de sistemas operativos (incluyendo Solaris, Mac OS X y FreeBSD) utiliza una aproximación híbrida llamó "adaptive mutex". La idea es para utilizar un spinlock cuándo este intentando acceder un recurso cerrado por un hilo que corra actualmente, pero para dormir si el hilo no esta actualmente corriendo. (El último es siempre el caso en sistemas de procesador único.)[1]
OpenBSD intentó reemplazar los "spinlocks" con bloqueos de tickets que aplicaban el comportamiento " primero en entrar, primero en salir" , pero esto dio como resultado un mayor uso de la CPU en el kernel y aplicaciones más grandes, como Firefox , cada vez más lentas. [4] [5]
Véase también
- Espín ocupado
- Punto muerto
Referencias
- ↑ Operating System Concepts (Fourth edición). Addison-Wesley. 1994. p. 198. ISBN 0-201-59292-4.
Enlaces externos
- pthread_Documentación_de cerradura del espín de Las Especificaciones de Base de Grupo Abiertas Asunto 6, IEEE Std 1003.1, 2004 Edición
- Variedad de spinlock Implementaciones de Concurrency Caja
- Usuario "de artículo-Cerraduras de Espín del Nivel - Hilos, Procesa & IPC" por Gert Boddaert
- Papel "El Rendimiento de Alternativas de Cerradura del Espín para Multiprocesadores de Memoria Compartida" por Thomas E. Anderson
- Algoritmos "de papel para Sincronización Escalable encima Multiprocesadores de Memoria Compartida" por John M. Mellor-Crummey Y Michael L. Scott. Este papel recibió el 2006 Dijkstra Premio en Informática Distribuida.
- Espín-Cerradura de Espera por Jeffrey Richter
- Austria C++ SpinLock Referencia de Clase Archivado el 14 de mayo de 2011 en Wayback Machine.
- Interlocked Acceso variable(Windows)
- Sistemas operativos: Tres Piezas Fáciles (Capítulo: Cerraduras)
Datos: Q570276