Cortex M3 obsługuje użyteczną parę operacji operacyjnych (wspólnych również w wielu innych maszynach) o nazwie „Load-Exclusive” (LDREX) i „Store-Exclusive” (STREX). Koncepcyjnie operacja LDREX wykonuje ładowanie, ustawia także specjalny sprzęt, aby obserwować, czy załadowana lokalizacja może być zapisana przez coś innego. Wykonanie STREX na adres użyty przez ostatni LDREX spowoduje, że adres zostanie zapisany tylko wtedy, gdy nic innego nie zostanie napisane najpierw . Instrukcja STREX załaduje rejestr z wartością 0, jeśli sklep miał miejsce, lub 1, jeśli został przerwany.
Pamiętaj, że STREX jest często pesymistyczny. Istnieje wiele sytuacji, w których może zdecydować się nie prowadzić sklepu, nawet jeśli dane miejsce nie zostało dotknięte. Na przykład przerwanie między LDREX a STREX spowoduje, że STREX przyjmie, że obserwowana lokalizacja mogła zostać trafiona. Z tego powodu zwykle dobrym pomysłem jest zminimalizowanie ilości kodu między LDREX a STREX. Rozważmy na przykład coś takiego:
inline void safe_increment (uint32_t * addr)
{
uint32_t nowa_wartość;
zrobić
{
nowa_wartość = __ldrex (addr) + 1;
} while (__ strex (nowa_wartość, adres));
}
który kompiluje się do czegoś takiego:
; Załóżmy, że R0 zawiera dany adres; r1 zniszczony
lp:
ldrex r1, [r0]
dodaj r1, r1, # 1
strex r1, r1, [r0]
cmp r1, # 0; Sprawdź, czy niezerowa
bne lp
.. kod trwa
Przez większość czasu wykonywania kodu między LDREX i STREX nic się nie stanie, aby je „zakłócić”, więc STREX odniesie sukces bez zbędnych ceregieli. Jeśli jednak nastąpi natychmiastowe przerwanie po instrukcji LDREX lub ADD, STREX nie wykona zapisu, ale zamiast tego kod wróci do odczytu (ewentualnie zaktualizowanej) wartości [r0] i wyliczy nową wartość przyrostową w oparciu o to.
Wykorzystanie LDREX / STREX do tworzenia operacji takich jak safe_increment pozwala nie tylko zarządzać krytycznymi sekcjami, ale także w wielu przypadkach, aby uniknąć ich potrzeby.