Страницы

Поиск по вопросам

понедельник, 12 ноября 2018 г.

Order of volatile access is undefined in this statement

Имеются две volatile-переменные:
volatile uint32_t a; volatile uint32_t b;
Они объявлены как volatile, потому что могут измениться как в основной программе, так и в обработчике прерывания, так и устройствами на системной шине (такими как DMA). Если обе переменные участвуют в одном выражении, например:
uint32_t c = a + b;
то компилятор выдаёт предупреждение Order of volatile access is undefined in this statement. Как я понимаю, это означает, что неизвестно, какая переменная первой загрузится в регистр общего назначения, и возможна такая ситуация, когда переменная a загрузилась в регистр, сработало прерывание, изменило это переменную, а основная программа продолжает работать со старым значением. Некоторые источники рекомендую в таких ситуациях разбивать выражение на части, например:
uint32_t c = a; c += b;
но на мой взгляд, так мы лишь затыкаем компилятор, а не устраняем причину проблемы.
А теперь собственно вопрос. В программе обработчики прерываний постоянно периодически изменяют volatile-переменные, а основная программа выполняет математические преобразования. Как только пришло новое значение переменной, старое уже неинтересно. Можно ли в этом случае игнорировать предупреждение компилятора? Есть ли у этого предупреждения другие источники, о которых я не догадываюсь?


Ответ

В языке С порядок доступа к volatile объектам, наряду с вызовами функций ввода-вывода, является частью наблюдаемого поведения (observable behavior) программы. Поэтому данное предупреждение просто выглядит как предупреждение от педантичного компилятора, который говорит, что наблюдаемое поведение программы в данном случае однозначно не определено.
Компилятор прав - оно действительно не определено однозначно. Но компилятор, разумеется, не знает, какие грани наблюдаемого поведения являются действительно важными для специфики вашей программы, а какие нет, и выдает абстрактное педантичное предупреждение.
Если в данном случае для вас порядок доступа к этим переменным действительно важен, тогда предупреждение вполне оправданно. Если же вы не видите проблем с любым возможным порядком доступа, то перепишите код чисто ради устранения предупреждения от компилятора.
Понятно, что в описанной вами ситуации, при модификации a и b из независимых линий исполнения (потоки, прерывания и т.п.) и при отсутствии какой-либо синхронизации, будет наблюдаться выраженный data race. А уж смертелен ли этот data race для вашего приложения - вам виднее. Если вы захотите избавиться от этого data race, то тут одним подавлением предупреждений не обойдешься - придется организовывать ту или иную форму синхронизации доступа к этой паре.

Комментариев нет:

Отправить комментарий