Algunas veces es posible eliminar el bloqueo. Considera el siguiente caso
del código del cortafuegos 2.2, que inserta un elemento en una lista
simplemente enlazada en el contexto de usuario:
new->next = i->next;
i->next = new;
Aquí el autor (Alan Cox, que sabía lo que estaba haciendo) asume
que el asignamiento de punteros es atómico. Esto es importante,
porque los paquetes de red atravesarían esta lista en bottom halves
sin un bloqueo. Dependiendo del tiempo exacto, ellos verían el nuevo
elemento en las lista con un puntero next
válido, o no verían la lista todavía. Aún se requiere un bloqueo
contra otras CPUs insertando o borrando de la lista, por supuesto.
Por supuesto, las escrituras deben estar
en este orden, en otro caso el nuevo elemento aparece en la lista
con un puntero next inválido, y alguna
otra CPU iterando en el tiempo equivocado saltará a través de él
a la basura. Porque las modernas CPUs reordenan, el código de
Alan actualmente se lee como sigue:
new->next = i->next;
wmb();
i->next = new;
La función wmb() es una barrera de escritura de
memoria (include/asm/system.h):
ni el compilador ni la CPU permitirán alguna escritura a memoria después
de que wmb() sea visible a otro hardware antes de que
alguna otra escritura se encuentre antes de wmb().
Como i386 no realiza reordenamiento de escritura, este bug nunca
fue mostrada en esta plataforma. Es otras plataformas SMP, de cualquier
forma, si que fue mostrado.
También hay rmb() para ordenamiento de lectura:
para asegurar que cualquier lectura previa de una variable ocurre antes
de la siguiente lectura. La macro simple mb()
combina rmb() y wmb().
Algunas operaciones atómicas están definidas para actuar como
una barrera de memoria (esto es, como la macro mb(),
pero si dudas, se explícito.
También, las operaciones de spinlock actuan como barreras
parciales: las operaciones después de obtener un spinlock nunca
serán movidas para preceder a la llamada spin_lock(),
y las operaciones antes de liberar un spinlock nunca serán movidas
después de la llamada spin_unlock().