Риск, который вы запускаете в описываемом вами сценарии (чтение из памяти для регистрации, обновление регистра, запись в память и переключение контекста между этими операциями), заключается в том, что вы можете потерять обновление, выполненное в другом контексте. 1001 *
Например:
main context:
read i (=10) from memory to register R1
add 5 to R1
<interrupt. Switch to interrupt context>
read i (=10) from memory to register R1
add 10 to R1
write R1 to i in memory (i = 20)
<end of interrupt. Back to main context>
write R1 to i in memory (i = 15)
Как видите, обновление от прерывания потеряно.
Еще более серьезная проблема может возникнуть, если вашему типу требуется несколько операций для записи его в память, а прерывание происходит в середине операции записи.
Например:
main context:
read first half of i (=10) from memory to register R1
read second half of i (=10) from memory to register R2
add 5 to R1/R2 pair
write R1 to first half of i in memory
<interrupt. Switch to interrupt context>
read first half of i (= ??) from memory to register R1
read second half of i (= ??) from memory to register R2
add 10 to R1/R2 pair
write R1 to first half of i in memory
write R2 to second half of i in memory
<end of interrupt. Back to main context>
write R2 to second half of i in memory
Здесь нет информации о том, какое значение я получу.
При sig_atomic_t
эта вторая проблема не может возникнуть, потому что тип гарантированно использует атомарные операции чтения / записи.