Безопасно ли делиться изменчивой переменной между основной программой и ISR в C?

Можно ли разделить выровненную целочисленную переменную, не превышающую естественное слово процессора, с изменчивым квалификатором между основной программой и ISR в C? Гарантировано ли, что никакие рваные чтения или записи не могут произойти?

    Ключевое слово volatile не подразумевает атомарность – это просто гарантирует, что переменная явно прочитана и не предполагается, что она не изменилась. Для безопасного совместного доступа без какого-либо другого механизма защиты переменная должна быть как атомарной, так и объявленной volatile .

    Компилятор может документировать типы, которые являются атомарными для любой конкретной цели, и может определять sig_atomic_t для этой цели.

    В целом, возможно, разумно предположить, что ваш компилятор не будет делать ничего извращенного и разбивать выровненное слово, где набор инструкций допускает атомное чтение. Следует соблюдать осторожность при переносе кода между платформами – такой код низкого уровня следует рассматривать как целевую и не переносную.

    Что касается ключевого слова volatile , то он просто защищает от возможных неправильных оптимизаций компилятором. Это не помогает в обеспечении безопасности streamов.

    Независимо от того, является ли поточно-безопасным использование общей переменной заданного размера, до компилятора. Нет никаких гарантий того, что доступ является атомарным. Например, компилятор может загрузить переменную в регистр перед дальнейшей обработкой, а затем записать ее обратно в память. В основном это зависит от набора инструкций процессора. Если вы хотите быть уверенным, вам нужно будет проверить дизассемблированный код или написать код на ассемблере.

    В противном случае вы можете сделать «мьютекс бедных» с помощью bool. Это работает только для конкретного случая ISR микроcontrollerов, которые не могут быть прерваны другими прерываниями. Поскольку вы знаете, что ISR не может быть прерван, вы можете сделать это:

     static volatile bool busy; static volatile uint16_t shared; void isr (void) { if(!busy) { shared = something; } } void main (void) { ... busy = true; do_something(shared); busy = false; ... } 

    При таком подходе не имеет значения, являются ли busy или shared атомарными или нет. Независимо от того, где триггеры прерывания, shared не будут уничтожены в середине доступа.

    Нет никакой гарантии, что любая общая целочисленная переменная будет записана и прочитана атомарно. Если вам нужна такая гарантия, вы должны использовать тип sig_atomic_t . Это единственный тип с такой гарантией.

    Из стандарта C99 7.14:

    2 Определенный тип

    sig_atomic_t

    который является (возможно, волатильным) целым типом объекта, к которому можно получить доступ как к атомному объекту, даже при наличии асинхронных прерываний.

    Проверьте свой компилятор. ISR нестандартны. Кроме того, у C нет реального понятия «естественное слово процессора», кроме, быть может, int .

    Ответ «иногда». Если либо ISR, либо основной процесс изменяет переменную, тогда вы в порядке. Однако, если оба манипулируют переменной, что-то вроде

     main Var = Var + 10 ISR Var = Var + 10 

    Тогда кто знает? Вы считаете, что конечным результатом будет var + 20, но если в сборке последовательность

     Main - Get Var ISR - Get Var Add 10 Store Var Return Add 10 Store Var 

    Тогда окончательный результат будет 10, а не 20

    Поскольку предыдущий плакат сказал, что для предотвращения этого вам понадобится код защиты.