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().