He releído a Herlihy y Wing muchas veces en los últimos 15 años. Es una lectura muy difícil. Y eso es lamentable, porque si bien hay algunas sutilezas en los bordes, la idea básica es bastante razonable.
En resumen: la linealización es como la serialización, pero con el requisito adicional de que la serialización respete restricciones de orden adicionales entre las transacciones. El objetivo es permitirle razonar rigurosamente sobre una estructura de datos atómicos individuales en lugar de tener que razonar sobre todo el sistema a la vez.
La linealización también es fácil de lograr: simplemente asocie un mutex con el objeto que desea linealizar. Cada transacción en ese objeto comienza bloqueando el mutex y termina desbloqueando el mutex.
Aquí están las definiciones que usaré:
Un sistema es serializable si se le da un conjunto de transacciones sobre un conjunto de datos, cualquier resultado de ejecutar las transacciones es el mismo que si las transacciones se ejecutaran en un orden secuencial, y las operaciones dentro de cada transacción están contenidas dentro de su transacción en el orden especificado por el código de la transacción.
La serialización no permite la apariencia de intercalación de operaciones entre diferentes transacciones, y requiere que el orden elegido de las transacciones satisfaga la causalidad (si la transacción A escribe el valor x, y la transacción B lee el valor x que A escribió, entonces la transacción A debe preceder a la transacción B en el orden en serie elegido.) Pero no dice nada sobre otras restricciones en el orden de las transacciones (en particular, no dice nada sobre los procesos y el orden en que los procesos perciben los eventos).
Hay otra idea relacionada que agrega restricciones sobre el orden en que los procesos ejecutan las operaciones (pero no habla de transacciones solo de operaciones de lectura / escritura individuales):
Un sistema es secuencialmente consistente si el resultado de cualquier ejecución es el mismo que si las operaciones de todos los procesos se ejecutaran en algún orden secuencial, y las operaciones de cada proceso individual aparecen en esta secuencia en el orden especificado por su programa. ( Lamport, "Cómo hacer una computadora multiprocesador que ejecute correctamente programas multiprocesador", IEEE T Comp 28: 9 (690-691), 1979 ).
Implícito en la definición de consistencia secuencial es que solo aceptamos órdenes secuenciales donde para cada ubicación de memoria (objeto) el orden secuencial de operaciones inducido obedece a la regla de que el valor devuelto por cada operación de lectura a la ubicación x
debe ser el mismo valor escrito por la operación de escritura inmediatamente anterior a la ubicación x
en el orden secuencial.
La linealización tiene las buenas intenciones de (a) combinar la noción de transacciones (de la serialización) con la noción de que los procesos esperan que las operaciones que emitan se completen en orden (de consistencia secuencial) y (b) reducir los criterios de corrección para hablar sobre cada objetar de forma aislada, en lugar de obligarlo a razonar sobre el sistema en su conjunto. (Me gustaría poder decir que la implementación de mi objeto es correcta incluso en un sistema donde hay otros objetos que no son linealizables). Creo que Herlihy y Wing podrían haber estado tratando de definir rigurosamente un monitor .
La parte (a) es "fácil": un requisito de coherencia secuencial sería que las transacciones en el objeto emitido por cada proceso aparezcan en la secuencia resultante en el orden especificado por el programa. Un requisito similar a la serialización sería que las transacciones en el objeto sean mutuamente excluyentes (se pueden serializar).
La complejidad proviene del objetivo (b) (poder hablar sobre cada objeto independientemente de todos los demás).
En un sistema con varios objetos, es posible que las operaciones en el objeto B impongan restricciones en el orden en el que creemos que las operaciones fueron invocadas en el objeto A. Si observamos el historial completo del sistema, estaremos limitados a ciertos órdenes secuenciales, y tendrá que rechazar a los demás. Pero queríamos un criterio de corrección que pudiéramos utilizar de forma aislada (razonamiento sobre lo que le sucede al objeto A sin apelar al historial del sistema global).
Por ejemplo: suponga que estoy tratando de discutir sobre la corrección del objeto A, que es una cola, suponga que el objeto B es una ubicación de memoria y suponga que tengo los siguientes historiales de ejecución: Hilo 1: A.enqueue (x), A. dequeue () (devuelve y). Hilo 2: A.enqueue (y), A.dequeue () (devuelve x). ¿Existe un entrelazado de eventos que permita que esta implementación de la cola sea correcta? Si:
Thread 1 Thread 2
A.enqueue(x) ...
... A.enqueue(y)
... A.dequeue() (returns x)
A.dequeue(y) (returns y) ...
Pero ahora, ¿qué pasa si el historial ( incluido el objeto B ) es: B comienza con el valor 0. Hilo 1: A.enqueue (x), A.dequeue () (devuelve y), B.write (1). Hilo 2: B.read () (devuelve 1) A.enqueue (y), A.dequeue () (devuelve x).
Thread 1 Thread 2
A.enqueue(x) ...
A.dequeue() (returns y) ... (uh oh!)
B.write(1) ...
... B.read() (returns 1)
... A.enqueue(y)
... A.dequeue() (returns x)
Ahora nos gustaría que nuestra definición de "corrección" diga que este historial indica que nuestra implementación de A es defectuosa o que nuestra implementación de B es defectuosa, porque no hay serialización que "tenga sentido" (o bien el Tema 2 debe leerse) un valor de B que aún no se ha escrito, o el subproceso 1 necesita eliminar un valor de A que aún no se ha puesto en cola.) Entonces, aunque nuestra serialización original de las transacciones en A parecía razonable, si nuestra implementación permite un historial como el segundo, entonces es claramente incorrecto.
Por lo tanto, las restricciones que agrega la linealización son bastante razonables (y necesarias incluso para estructuras de datos simples como las colas FIFO). Son cosas como: "su implementación no debe permitir dequeue () un valor que no se pondrá en cola () hasta algún tiempo en el futuro." La linealización es bastante fácil (y natural) de lograr: simplemente asocie un mutex con su objeto, y cada transacción comienza bloqueándose y termina desbloqueándose. El razonamiento sobre la linealización comienza a ser complicado cuando intenta implementar su atomicidad con técnicas sin bloqueo o sin bloqueo o sin esperar en lugar de simples mutexes.
Si está interesado en algunos consejos sobre la literatura, encontré lo siguiente (aunque creo que la discusión sobre el "tiempo real" es una de las pistas falsas que hacen que la linealización sea más difícil de lo necesario). Https: // stackoverflow.com/questions/4179587/difference-between-linearizability-and-serializability