Чтение внутренних критических разделов из ISR

Нужно ли защищать чтение изменчивых переменных в критических секциях при использовании прерываний? Или критические секции необходимы только при одновременной записи переменных?

Вот пример переменной, записанной в ISR и защищенной критической секцией:

void loop() {
    portENTER_CRITICAL(&mux);
    uint other = variable_written_from_isr + 1;
    portEXIT_CRITICAL(&mux);
}

Что произойдет, если прерывание изменит variable_writing_from_isr во время его чтения? Будет ли что-нибудь хуже, если возникнут несоответствия?

Вот противоположный пример, когда переменная записывается из прерывания и считывается из цикла (или задачи):

void IRAM_ATTR handleInterrupt() {
    portENTER_CRITICAL_ISR(&mux);
    uint other = variable_written_from_loop + 1;
    portEXIT_CRITICAL_ISR(&mux);
}

Обратите внимание, что я знаю о stdatomic. Меня главным образом интересует понимание поведения одновременного доступа в контексте прерываний.

, 👍0

Обсуждение

Что произойдет, если прерывание изменит переменную_variable_writing_from_isr во время чтения? ..... прерывания не будет, потому что portENTER_CRITICAL(&mux); отключает прерывания, @jsotola

Спасибо, что указали на это. Я ожидал, что выполнение прерывания будет отложено до выхода из критической секции., @DurandA


2 ответа


Лучший ответ:

0

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

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

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

Какие инструкции могут быть атомарными, во многом зависит от архитектуры, над которой вы работаете. Единственный реальный способ убедиться в этом — скомпилировать код на ассемблере и проверить, что получится. Конечно, это означает изучение языка ассемблера выбранной вами архитектуры.

Однако: если есть сомнения, используйте критический раздел. Лучше быть в безопасности, чем потом сожалеть. Но делайте эти критические секции как можно короче, чтобы не беспокоить прерывания больше, чем необходимо.

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

,

0

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

,