El Cortex M3 admite un par de operaciones de operaciones útiles (comunes en muchas otras máquinas también) llamadas "Load-Exclusive" (LDREX) y "Store-Exclusive" (STREX). Conceptualmente, la operación LDREX realiza una carga, también establece un hardware especial para observar si la ubicación que se cargó podría estar escrita por otra cosa. Realizar un STREX en la dirección utilizada por el último LDREX hará que esa dirección se escriba solo si nada más la escribió primero . La instrucción STREX cargará un registro con 0 si la tienda se llevó a cabo, o 1 si se canceló.
Tenga en cuenta que STREX es a menudo pesimista. Hay una variedad de situaciones en las que podría decidir no realizar la tienda, incluso si la ubicación en cuestión no hubiera sido tocada. Por ejemplo, una interrupción entre un LDREX y un STREX hará que el STREX asuma que la ubicación que se está viendo podría haber sido golpeada. Por esta razón, generalmente es una buena idea minimizar la cantidad de código entre LDREX y STREX. Por ejemplo, considere algo como lo siguiente:
inline void safe_increment (uint32_t * addr)
{
uint32_t new_value;
hacer
{
nuevo_valor = __ldrex (addr) + 1;
} while (__ strex (nuevo_valor, addr));
}
que compila algo como:
; Suponga que R0 contiene la dirección en cuestión; r1 destrozado
lp:
ldrex r1, [r0]
agregue r1, r1, # 1
strex r1, r1, [r0]
cmp r1, # 0; Prueba si no es cero
bne lp
.. el código continúa
La gran mayoría de las veces que se ejecuta el código, nada sucederá entre LDREX y STREX para "perturbarlos", por lo que STREX tendrá éxito sin más preámbulos. Sin embargo, si ocurre una interrupción inmediatamente después de la instrucción LDREX o ADD, STREX no realizará el almacenamiento, sino que el código volverá a leer el valor (posiblemente actualizado) de [r0] y calculará un nuevo valor incrementado basado en eso.
El uso de LDREX / STREX para formar operaciones como safe_increment hace posible no solo administrar secciones críticas, sino también, en muchos casos, evitar la necesidad de ellas.