O ( 1 ) no ayuda en sí mismo. En una estructura de datos sin bloqueo, debe haber una única instancia atómica cuando su estructura de datos parece cambiar. Todos los invariantes de representación deben estar vigentes tanto inmediatamente antes como inmediatamente después de ese instante atómico.
Esto significa que si está realizando una modificación en la estructura de datos, la característica importante es que puede hacer todas las modificaciones en una estructura de datos privada y luego intercambiar las modificaciones en una sola instrucción atómica.
La libertad de bloqueo suele ser más fácil cuando las estructuras de datos son inmutables ( puramente funcionales ). Simplemente mantenga un puntero global a la versión actual de la estructura de datos. Los lectores no necesitan bloquear nada. Las modificaciones a la estructura de datos se efectúan intercambiando el puntero global a una estructura de datos inmutable a otra.
Por ejemplo: si tiene un árbol equilibrado de árbol puramente funcional, usted:
- Registre el puntero global actual a la raíz del árbol.
- Cree un nuevo árbol que inserte o elimine un nodo. (Esto es logarítmico en tiempo y espacio en la cantidad de nodos actualmente en el árbol, e implica crear nuevos nodos desde el punto de modificación hasta la raíz, y solo señalar todo lo nuevo en las partes antiguas de la versión anterior de la estructura de datos. )
- Compare atómicamente e intercambie el puntero global a la raíz. (Tenga en cuenta que esto podría fallar si ha ocurrido otra modificación entre el momento en que registró el puntero raíz anterior y ahora. Si esto sucede, vuelva al paso 1 e intente nuevamente. Esto se denomina "control de concurrencia optimista").
Tenga en cuenta que la parte más importante es lo que dije anteriormente sobre la necesidad de mantener invariantes de representación. Por lo general, no es suficiente tener un algoritmo que atómicamente haga un cambio en el medio del árbol. ¿Por qué? Por ejemplo: puede tener un hilo lector que está en proceso de realizar un recorrido previo al pedido del árbol. Si modifica un nodo que es un antecesor del nodo que están leyendo actualmente, invalidará las condiciones previas que pensaron que habían aplicado. El lector debe poder trabajar con la estructura de datos exactamente como estaba antes de realizar el cambio, o exactamente como será después de que haya realizado el cambio. No hay algo en el medio.
Editar : como señaló @Raphael, existen técnicas para hacer que las estructuras de datos mutables estén libres de bloqueo. Una prueba por construcción de que esto siempre se puede hacer es: siempre que tenga un puntero global único a la "parte superior" de su estructura de datos, incluso si es mutable, siempre puede copiar toda la estructura de datos, realice sus modificaciones en el copie y luego, utilizando un control de concurrencia optimista, intente comparar e intercambiar el puntero a su estructura de datos recién creada para obtener el original. La belleza de las estructuras de datos funcionales basadas en árboles es que mantienen el costo de copiar en de una estructura de datos de tamaño .O ( N )O ( l o g( N) )O ( N)