Articulo de referencia

Prueba y configuración

En informática , la instrucción de prueba y establecimiento (test-and-set ) se utiliza para escribir (establecer) un valor de indicador en una ubicación de memoria y devolver su...

En informática , la instrucción de prueba y establecimiento (test-and-set ) se utiliza para escribir (establecer) un valor de indicador en una ubicación de memoria y devolver su valor anterior como una única operación atómica (es decir, no interrumpible ). El proceso que realiza la llamada puede entonces "probar" el resultado para ver si el estado se modificó. Si varios procesos pueden acceder a la misma ubicación de memoria y si un proceso está realizando una prueba y establecimiento, ningún otro proceso puede iniciar otra prueba y establecimiento hasta que la del primer proceso haya finalizado. Una unidad central de procesamiento (CPU) puede utilizar una instrucción de prueba y establecimiento proporcionada por otro componente electrónico , como la memoria RAM de doble puerto ; la propia CPU también puede ofrecer una instrucción de prueba y establecimiento.

Se puede construir un bloqueo utilizando una instrucción atómica de prueba y establecimiento [ 1 ] de la siguiente manera:

Este código asume que la ubicación de memoria se inicializó a 0 en algún momento antes de la primera prueba y establecimiento. El proceso que llama obtiene el bloqueo si el valor anterior era 0; de lo contrario, el bucle while se queda esperando para adquirir el bloqueo. Esto se denomina spinlock . En cualquier momento, el poseedor del bloqueo puede simplemente restablecer la ubicación de memoria a 0 para liberar el bloqueo y permitir que otro lo adquiera; esto no requiere ningún manejo especial, ya que el poseedor "es dueño" de esta ubicación de memoria. " Prueba y prueba y establecimiento " es otro ejemplo.

Maurice Herlihy (1991) demostró que test-and-set (comparando de 1 bit) tiene un número de consenso finito y puede resolver el problema de consenso sin espera para como máximo dos procesos concurrentes. [ 2 ] En contraste, compare-and-swap (comparando de 32 bits) ofrece una solución más general a este problema, y ​​en algunas implementaciones también está disponible compare-and-swap más amplio (comparando de 64 o 128 bits) para una utilidad extendida.

Implementación de hardware de prueba y ajuste

Las instrucciones de prueba y configuración de la DPRAM pueden funcionar de diversas maneras. A continuación, se presentan dos variantes que describen una DPRAM con exactamente dos puertos, lo que permite que dos componentes electrónicos independientes (como dos CPU) accedan a todas las ubicaciones de memoria de la DPRAM.

Variación 1

Cuando la CPU 1 emite una instrucción de prueba y establecimiento, la DPRAM primero registra internamente esta acción almacenando la dirección de la ubicación de memoria en un lugar especial. Si en ese momento la CPU 2 emite una instrucción de prueba y establecimiento para la misma ubicación de memoria, la DPRAM primero verifica su registro interno, reconoce la situación y emite una interrupción de OCUPACIÓN, que le indica a la CPU 2 que debe esperar y volver a intentarlo. Esta es una implementación de espera activa o bloqueo de giro mediante el mecanismo de interrupción. Dado que todo esto ocurre a la velocidad del hardware, la CPU 2 espera para salir del bloqueo de giro es muy corta.

Independientemente de si la CPU 2 intentaba acceder a la ubicación de memoria, la DPRAM realiza la comprobación indicada por la CPU 1. Si la comprobación es exitosa, la DPRAM asigna a la ubicación de memoria el valor proporcionado por la CPU 1. A continuación, la DPRAM borra la "nota interna" que indicaba que la CPU 1 estaba escribiendo allí. En este punto, la CPU 2 podría realizar una comprobación y asignación, la cual sería exitosa.

Variación 2

La CPU 1 emite una instrucción de prueba y escritura para asignar la dirección de memoria A. La DPRAM no almacena inmediatamente el valor en la dirección A, sino que simultáneamente transfiere el valor actual a un registro especial, al tiempo que asigna un valor de indicador especial a la dirección A. Si en este punto la CPU 2 emite una instrucción de prueba y escritura en la dirección A, la DPRAM detecta el valor del indicador especial y, como en la Variación 1, genera una interrupción de OCUPACIÓN.

Independientemente de si la CPU 2 intentaba acceder a la ubicación de memoria, la DPRAM realiza la comprobación de la CPU 1. Si la comprobación es exitosa, la DPRAM asigna a la ubicación de memoria A el valor especificado por la CPU 1. Si la comprobación falla, la DPRAM copia el valor del registro especial a la ubicación de memoria A. Cualquiera de estas operaciones borra el valor del indicador especial. Si la CPU 2 realiza ahora una comprobación y asignación, esta tendrá éxito.

Implementación de software de prueba y configuración

Algunos conjuntos de instrucciones tienen una instrucción de lenguaje máquina atómica de prueba y establecimiento . Ejemplos de ello son x86 [ 3 ] e IBM System/360 y sus sucesores (incluida z/Architecture ). [ 4 ] Aquellos que no la tienen aún pueden implementar una prueba y establecimiento atómicos mediante una instrucción de lectura-modificación-escritura o de comparación e intercambio .

La instrucción de prueba y establecimiento, cuando se usa con valores booleanos, utiliza una lógica similar a la que se muestra en la siguiente función, con la salvedad de que la función debe ejecutarse de forma atómica . Es decir, ningún otro proceso debe poder interrumpir la función durante su ejecución, evitando así que vea un estado que solo existe mientras la función se ejecuta. Esto requiere soporte de hardware; no se puede implementar como se muestra. Sin embargo, el código mostrado ayuda a explicar el comportamiento de la instrucción de prueba y establecimiento. NOTA: En este ejemplo, se asume que 'lock' se pasa por referencia (o por nombre), pero la asignación a 'initial' crea un nuevo valor (no solo copia una referencia).

función TestAndSet(bloqueo de referencia booleana) { booleano inicial = bloqueo; bloqueo = verdadero; devolver inicial; }

El código mostrado no solo no es atómico, en el sentido de la instrucción de prueba y establecimiento, sino que también difiere de las descripciones de prueba y establecimiento de hardware DPRAM mencionadas anteriormente. Aquí, el valor que se establece y la prueba son fijos e invariables, y el valor se actualiza independientemente del resultado de la prueba, mientras que para la prueba y establecimiento de DPRAM, la memoria se establece solo cuando la prueba tiene éxito, y el valor a establecer y la condición de prueba son especificados por la CPU. Aquí, el valor a establecer solo puede ser 1, pero si 0 y 1 se consideran los únicos valores válidos para la ubicación de memoria, y "el valor es distinto de cero" es la única prueba permitida, entonces esto equivale al caso descrito para el hardware DPRAM (o, más específicamente, el caso DPRAM se reduce a esto bajo estas restricciones). Desde ese punto de vista, esto puede, correctamente, llamarse "prueba y establecimiento" en el sentido completo y convencional del término. Lo esencial a tener en cuenta es la intención y el principio general de la comprobación y asignación de valores: un valor se comprueba y se asigna en una operación atómica, de modo que ningún otro hilo o proceso del programa puede modificar la ubicación de memoria de destino después de la comprobación, pero antes de su asignación. (Esto se debe a que la ubicación solo debe asignarse si actualmente tiene un valor determinado, no si lo tuvo en algún momento anterior).

En el lenguaje de programación C , la implementación sería la siguiente:

#define BLOQUEADO 1int test_and_set ( int * lock_ptr ) { int old_value ;// -- Inicio del segmento atómico -- // Esto debe interpretarse como pseudocódigo solo con fines ilustrativos. // La compilación tradicional de este código no garantiza la atomicidad, el // uso de memoria compartida (es decir, valores no almacenados en caché), la protección contra las optimizaciones del compilador , // u otras propiedades requeridas. old_value = * lock_ptr ; * lock_ptr = LOCKED ; // -- Fin del segmento atómico --devolver valor_antiguo ; }

El código también muestra que en realidad hay dos operaciones: una lectura-modificación-escritura atómica y una prueba. Solo la lectura-modificación-escritura necesita ser atómica. (Esto es cierto porque retrasar la comparación de valores, independientemente del tiempo, no cambiará el resultado de la prueba una vez que se haya obtenido el valor a probar. Una vez que el código escribe el valor inicial, el resultado de la prueba ya está establecido, incluso si aún no se ha calculado, por ejemplo, mediante el operador ==).

Exclusión mutua mediante prueba y conjunto

Una forma de implementar la exclusión mutua es mediante el uso de un bloqueo basado en prueba y conjunto [ 5 ] [ 6 ] de la siguiente manera:

Implementación en pseudo-C de un bloqueo de giro

bloqueo entero volátil = 0 ;void critical () {// Bloqueo de giro: bucle infinito hasta que consigamos el bloqueo. // Sabemos que el bloqueo se obtuvo correctamente después de salir // de este bucle while porque la función test_and_set() bloquea // el bloqueo pero devuelve el valor de bloqueo _anterior_. // Si (y solo si) el valor de bloqueo anterior era 1, entonces el bloqueo // ya estaba bloqueado por otro hilo o proceso, por lo que permanecemos en el // bucle y volvemos a intentarlo. // Cuando el valor de bloqueo anterior era 0, eso indica que el // bloqueo **no** estaba bloqueado antes de que lo bloqueáramos. Ahora **está** bloqueado // porque _nosotros_ lo bloqueamos, por lo que poseemos el bloqueo y podemos salir del bucle de giro. while ( test_and_set ( & lock ) == 1 );Sección crítica // Solo un proceso puede estar en esta sección a la vez// Libera el bloqueo cuando termines con la sección crítica. // Era 1 (porque lo bloqueamos). // Cualquier otro proceso que lo haya "cambiado" desde entonces // no estaba en la sección crítica, por lo que los // otros procesos también lo establecieron en 1, pero // no obtuvieron el bloqueo ni entraron en la // sección crítica, y (o bien se rindieron o) // siguen esperando en sus propios bucles de espera. bloqueo = 0 ; }

La variable `lock` es una variable compartida, es decir, todos los procesadores/hilos pueden acceder a ella. Nótese la palabra clave `volatile` . En ausencia de `volatile`, el compilador o la CPU podrían optimizar el acceso a la variable `lock` o usar valores en caché, lo que haría que el código anterior fuera erróneo. Por otro lado, y lamentablemente, la presencia de `volatile` no garantiza que las lecturas y escrituras se guarden en memoria. Algunos compiladores establecen barreras de memoria para asegurar que las operaciones se guarden en memoria, pero dado que la semántica de ` volatile` en C/C++ es bastante ambigua, no todos los compiladores lo harán.

Esta función de bloqueo de giro puede ser llamada por múltiples procesos, pero se garantiza que solo un proceso estará en la sección crítica a la vez. Los demás procesos seguirán esperando hasta obtener el bloqueo. Es posible que un proceso nunca obtenga el bloqueo. En tal caso, entrará en un bucle infinito. Esta es una desventaja de la implementación de bloqueo de giro, ya que no garantiza la equidad. Estos problemas se explican con más detalle en la sección de rendimiento .

Implementación del ensamblaje

enter_region: ; Una etiqueta "saltar a"; punto de entrada de la función.tsl reg , flag ; Bloqueo de prueba y establecimiento; flag es la ; variable compartida; se copia ; en el registro reg y flag ; luego se establece atómicamente a 1.cmp reg , #0 ; ¿Era la bandera cero en entry_region?jnz enter_region ; Saltar a enter_region si ; reg no es cero; es decir, ; flag no era cero al entrar.ret ; Salida; es decir, la bandera era cero en ; entrada. Si llegamos aquí, tsl ; la habrá establecido distinta de cero; por lo tanto, ; hemos reclamado el recurso ; asociado con la bandera.leave_region: mover bandera , #0; almacenar 0 en bandera ret ; devolver al llamador

Aquí tslhay una instrucción atómica y flages la variable de bloqueo. El proceso no regresa a menos que adquiera el bloqueo.

Evaluación del rendimiento de las cerraduras de prueba y ajuste.

Las cuatro métricas de evaluación principales para los bloqueos en general son la latencia de adquisición de bloqueo sin contención, el tráfico del bus, la equidad y el almacenamiento. [ 7 ]

Las pruebas estandarizadas obtienen puntuaciones bajas en dos de ellas: el elevado tráfico de autobuses y la injusticia.

Cuando el procesador P1 obtiene un bloqueo y el procesador P2 también lo espera, P2 continúa realizando transacciones en el bus para intentar adquirirlo. Una vez que un procesador obtiene un bloqueo, todos los demás procesadores que también desean obtenerlo siguen intentándolo mediante transacciones repetidas en el bus hasta conseguirlo. Esto aumenta significativamente el tráfico del bus requerido para la operación de prueba y establecimiento. Esto ralentiza todo el tráfico proveniente de fallos de caché y coherencia . Ralentiza la sección en general, ya que el tráfico se satura con intentos fallidos de adquisición de bloqueo. La operación de prueba y establecimiento supone una mejora con respecto a TSL, ya que no inicia solicitudes de adquisición de bloqueo de forma continua.

Al considerar la equidad, analizamos si un procesador tiene una oportunidad justa de adquirir el bloqueo una vez liberado. En una situación extrema, el procesador podría sufrir un bloqueo insostenible, es decir, podría no ser capaz de adquirirlo durante un período prolongado, incluso después de haber quedado libre durante ese tiempo.

El almacenamiento adicional que requiere TSL es prácticamente nulo, ya que solo se necesita un bloqueo. La latencia sin contención también es baja, puesto que solo se requiere una instrucción atómica y una bifurcación.

Véase también

Referencias

  1. Anderson, TE (1990-01-01). "El rendimiento de las alternativas de bloqueo de giro para multiprocesadores de dinero compartido". IEEE Transactions on Parallel and Distributed Systems . 1 (1): 6– 16. doi : 10.1109/71.80120 . ISSN 1045-9219 . 
  2. Herlihy, Maurice (enero de 1991). "Sincronización sin espera" (PDF) . ACM Trans. Program. Lang. Syst . 13 (1): 124– 149. CiteSeerX 10.1.1.56.5659 . doi : 10.1145/114005.102808 . S2CID 2181446. Consultado el 20 de mayo de 2007 .  
  3. "BTS—Bit Test and Set" . www.felixcloutier.com . Consultado el 21 de noviembre de 2016 .
  4. "Centro de conocimiento de IBM" . www.ibm.com . Consultado el 21 de noviembre de 2016 .
  5. Remzi H. Arpaci-Dusseau y Andrea C. Arpaci-Dusseau (2015). Sistemas operativos: tres piezas fáciles ( ed. 0.91). Libros Arpaci-Dusseau. 
  6. Solihin, Yan (2009). Fundamentos de la arquitectura de computadoras paralelas : sistemas multichip y multinúcleo . pág. 252. ISBN   9780984163007.
  7. ^ Solihin, Yan (2016). Fundamentos de la Arquitectura Paralela . Boca Ratón, FL: CRC Press. ISBN 978-1-4822-1118-4.