¿Límites en las colecciones sin bloqueo?

10

David Rodríguez - dribeas escribió en un comentario en StackOverflow que "No todas las colecciones se pueden implementar sin bloqueos". No estoy seguro de si esto es cierto, y no puedo encontrar pruebas de ninguna manera.

Esta declaración no es muy precisa, pero permítanme tratar de reformularla de una manera un poco más formal: para cada tipo de colección C, existe un tipo de colección CLF sin bloqueo que ofrece el mismo conjunto de operaciones, y donde cada operación en CLF tiene la misma complejidad big-O que la operación correspondiente en C.

No espero una transformación, por cierto.

MSalters
fuente
1
Como no experto, me pregunto si "sin bloqueo" se puede definir rigurosamente.
Tsuyoshi Ito
1
@Suresh: ¿Tal vez un sinónimo de "estructura de datos"?
Tsuyoshi Ito
2
¿Qué sucede si simplemente toma una implementación sin bloqueo de STM (memoria transaccional de software) e implementa cualquier estructura de datos además de eso?
Jukka Suomela
55
@ Tsuyoshi: Creo que no hay una definición formal de sin bloqueo. Informalmente, significa que no utiliza la instrucción LOCK de la CPU, que es lenta, y se adhiere a la comparación e intercambio más rápidos. Dado que un BLOQUEO se puede simular con comparar e intercambiar, es difícil establecer un límite rígido entre "esencialmente se usa comparar e intercambiar aquí para simular un bloqueo (o una transacción para el caso)" y "oh, esto es un uso realmente inteligente de comparar e intercambiar, y no parece en absoluto como si simulara una operación de nivel superior que conocemos ".
Radu GRIGore
1
Por lo que yo entiendo, sin bloqueo se entiende aquí como sinónimo de no bloqueo. Esto no implica las LOCKinstrucciones de la CPU, sino el planificador de subprocesos, a través de mutexes / semaphores / etc.
MSalters

Respuestas:

11

Como estaba algo confundido, empiezo aclarando algunos conceptos en la pregunta.

Colección . No veo ninguna razón para pasar el tiempo definiendo rigurosamente lo que significa "colección" cuando simplemente podemos preguntar qué sucede con las estructuras de datos en general. Una estructura de datos ocupa un trozo de memoria y tiene algunas operaciones que pueden acceder a esa memoria y que los usuarios pueden invocar . Estos usuarios pueden ser procesadores distintos o simplemente hilos diferentes, no nos concierne. Lo único que importa es que puedan ejecutar operaciones en paralelo.

Sin bloqueo . Herlihy y Boss dicen que una estructura de datos está libre de bloqueos cuando un usuario que falla no impide usos adicionales de la estructura de datos. Por ejemplo, imagine que uno vierte agua en un procesador que está insertando un nodo en un conjunto ordenado. Bueno, si otros procesadores intentan insertarse más tarde en ese conjunto ordenado, deberían tener éxito. ( Edición: De acuerdo a esta definición, es el caso que si utiliza una estructura de datos cerraduras entonces no es lock-libre, pero es no el caso de que si una estructura de datos no utiliza las cerraduras entonces es libre de bloqueo).

Con esta definición, creo que Herlihy y Boss básicamente dicen que la respuesta es convertir las regiones críticas en transacciones.

Pero, usted puede preguntar, ¿tiene esto la misma complejidad? No estoy seguro de que la pregunta tenga sentido. Considere push(x) { lock(); stack[size++] = x; unlock(); }. ¿Es esta una operación de tiempo constante? Si ignora la operación de bloqueo y, por lo tanto, otros usuarios, puede responder SÍ. Si no desea ignorar a otros usuarios, entonces realmente no hay forma de decir si la inserción se ejecutará en tiempo constante. Si subes un nivel y ves cómo un algoritmo particular usa la pila, entonces podrías decir que el empuje siempre tomará un tiempo constante (medido ahora en términos de lo que sea que sea la entrada de tu algoritmo paralelo). Pero eso realmente es una propiedad de su algoritmo, por lo que no tiene sentido decir que push es una operación de tiempo constante.

En resumen, si ignora cuánto espera un usuario que ejecuta una operación a otros usuarios, el uso de transacciones en lugar de regiones críticas responde a su pregunta afirmativamente. Si no ignora el tiempo de espera, debe observar cómo se utiliza la estructura de datos.

Radu GRIGore
fuente
No estoy muy seguro de si realmente puede considerar que la pushoperación como se indicó anteriormente no es una operación de tiempo constante. Para un número fijo de procesadores, y una implementación común lockque garantiza que no haya inanición, la operación anterior (en el peor de los casos, para cualquier procesador dado toma N_proc * O (1), que ingenuamente se puede suponer que es O (1) ( número de procesadores incluidos en la constante oculta.)
David Rodríguez - dribeas
nf(n)f
Bueno, el acceso a la memoria es un caso común de eso. La mayoría de los análisis de algoritmos asumen que el acceso a la memoria es O (1) independiente de la memoria utilizada; Las arquitecturas de memoria real (con cachés, etc.) se aproximan mejor por O (log N) donde N es la memoria utilizada.
MSalters
Si bien el supuesto de que el número de procesadores es una constante es bastante práctico, lo evitaré. Entonces, el problema es que la complejidad no puede analizarse de manera unidimensional, ya que el tamaño del problema aumentará tanto en el tamaño de la entrada como en el número de procesadores, los cuales son dimensiones ortogonales. Suponiendo un contenedor particular en la biblioteca estándar de C ++ (obviamente estoy eligiendo uno difícil) uno de los requisitos es que todos los elementos se mantengan en un bloque contiguo de memoria.
David Rodríguez - dribeas 01 de
Ahora, agregar un elemento al vector es una operación de tiempo constante amortizado (si no cabe en el bloque previamente asignado, la llamada tomará un tiempo lineal en el número de elementos en el contenedor, pero si el bloque de memoria reservado es adquirido siguiendo una secuencia exponencial, el costo amortizado es constante). Si implementa un contenedor seguro para subprocesos, bloquearía y luego realizaría el cambio, el costo de la operación es proporcional al costo de bloqueo, lo que realmente no sé ... pero en una primera aproximación puede considerar principalmente constante
David Rodríguez - dribeas 01 de
3

Creo que "COLECCIONES" significa "colas, pilas, listas vinculadas, árboles, ..."

De http://www.cl.cam.ac.uk/research/srg/netos/lock-free/

Mediante un diseño e implementación cuidadosos, es posible construir estructuras de datos que sean seguras para uso concurrente sin necesidad de administrar bloqueos o subprocesos de bloque. Estas estructuras de datos sin bloqueo pueden aumentar el rendimiento al permitir una mayor concurrencia y pueden mejorar la robustez al evitar algunos de los problemas causados ​​por la inversión de prioridad en la configuración local, o fallas de máquinas y enlaces en sistemas distribuidos.

La mejor introducción general a nuestros algoritmos sin bloqueo es la programación simultánea en papel sin bloqueos, actualmente en proceso de presentación, que cubre nuestros diseños de memoria transaccional de software basada en palabras de comparación y intercambio de varias palabras y memoria transaccional de software basada en objetos.

Si "sin bloqueo" significa "no use semáforos, mutex, monitores, ..." del sistema operativo, entonces creo (pero no soy un experto) que cada colección se puede hacer sin bloqueo usando lectura-escritura atómica modificar primitivas que deben ser compatibles con el hardware.

O()

Se puede encontrar documentación exhaustiva sobre el tema en línea:

http://www.google.it/search?q=lock+free+algorithm+filetype%3Apdf

(... y más referencias al final de cada documento)

Marzio De Biasi
fuente