O Cortex M3 suporta um par útil de operações (comum em muitas outras máquinas) chamado "Load-Exclusive" (LDREX) e "Store-Exclusive" (STREX). Conceitualmente, a operação LDREX executa uma carga, também define algum hardware especial para observar se o local que foi carregado pode ser gravado por outra coisa. A execução de um STREX no endereço usado pelo último LDREX fará com que esse endereço seja gravado apenas se nada mais o tiver escrito primeiro . A instrução STREX carregará um registro com 0 se a loja ocorreu ou 1 se foi abortada.
Observe que o STREX geralmente é pessimista. Existem várias situações em que pode decidir não executar a loja, mesmo que o local em questão não tenha sido realmente tocado. Por exemplo, uma interrupção entre um LDREX e STREX fará com que o STREX assuma que o local que está sendo observado pode ter sido atingido. Por esse motivo, geralmente é uma boa ideia minimizar a quantidade de código entre o LDREX e o STREX. Por exemplo, considere algo como o seguinte:
inline void safe_increment (uint32_t * addr)
{
uint32_t novo_valor;
Faz
{
new_value = __ldrex (endereço) + 1;
} while (__ strex (novo_valor, endereço));
}
que compila para algo como:
; Suponha que R0 mantenha o endereço em questão; r1 lixeira
lp:
ldrex r1, [r0]
adicione r1, r1, # 1
strex r1, r1, [r0]
cmp r1, # 0; Teste se diferente de zero
bne lp
.. código continua
Na grande maioria das vezes que o código é executado, nada acontece entre o LDREX e o STREX para "perturbá-los"; portanto, o STREX terá êxito sem mais delongas. Se, no entanto, ocorrer uma interrupção imediatamente após a instrução LDREX ou ADD, o STREX não executará o armazenamento, mas o código retornará para ler o valor (possivelmente atualizado) de [r0] e calcular um novo valor incrementado com base nisso.
O uso do LDREX / STREX para formar operações como safe_increment possibilita não apenas gerenciar seções críticas, mas também em muitos casos, para evitar a necessidade delas.