Цитата:Получается, что если мы на С читаем в локальную переменную из глобальной, а это выполняется за много ASM команд, то у нас запросто может прийти прерывание которое пишет эту же глобальную переменную и в результате мы можем прочитать начало старого значения а конец нового?
При любом многопоточном коде такое возможно - наличие разрешенных прерываний - это один из видов многопоточности.
Естественно, что доступ к объектам, который осуществляется неатомарным способом из нескольких потоков (например, за несколько команд) надо обрамлять в критические секции (вид этих критических секций может разнится от среды выполнения).
Следует понимать, что неатомарность доступа бывает везде. И если, например, на AVR на неатомарность можно наступить уже при работе с int (т.к. 16 бит), то на ARM это обычно проявляется при работе со структурами как с целыми объектами.
Обычно в среде различных RTOS есть специальные примитивы, которые позволяют обеспечивать быструю блокировку многопоточности для такого доступа. Следует, однако, иметь в виду, что блокировать шедуллер следует только на минимально возможное время - иначе могут возникнуть совершенно нежелательные задержки в работе других потоков. Если надо монополизировать доступ к какому-либо объекту на длительное время, то в средах RTOS рекомендуется использовать более продвинутые примитивы синхронизации - мьютексы и тому подобное.
Теперь о простом способе красивого написания атомарного кода (на Си). Я обычно пользуюсь таким макросом (пример для IAR'а в инкарнации ARM Cortex-M3)
//Содержимое подходящего .h-файла
#pragma inline=forced
static __istate_t get_INTERRUPT_and_CLI() {__istate_t s=__get_interrupt_state(); __disable_interrupt(); return s; }
#define ATOMIC_CODE() for(__istate_t __temp=get_INTERRUPT_and_CLI(),iter=0; iter<1; iter++,__set_interrupt_state(__temp))
//Использование
void foo(void)
{
...
ATOMIC_CODE()
{
//Этот код в пределах скобок будет выполнен с запрещенными прерываниями. После выхода из блока состояние прерываний будет восстановлено.
a++; //Кстати, если а - глобальная переменная, такой инкремент нифига не атомарен
}
...
}
Что делают функции __get_interrupt_state, __disable_interrupt и __set_interrupt_state, думаю, понятно само за себя. На самом деле пара __get/__set представляет из себя минимально возможный способ получить и восстановить состояние прерываний - обычно это одна-две команды на любой архитектуре.
Цикл в макросе оптимизатор полностью вычищает, т.к. его работа полностью предсказуема и представляет из себя одну итерацию.
Ну а в общем намного выше я рассказывал о прелестях регистровой архитектуры и правильным способом работы с переменными на процессорах с такой архитектурой - загрузили из ОЗУ в регистры, потрудились, выгрузили. Так вот в таком случае часто обеспечение атомарности упрощается - один атомарный блок в начале, один - в конце.
Цитата:Во всяком случае при написании мониторов для РК-86
Господин Peratron, Вам абы слово вставить? На РК-86 сигнал прерывания на процессор
не приходил никогда, ибо железно сидел на +5. А на вывод сигнализации о разрешении/запрете прерываний вообще был подвешен матюгальник. Ни о какой многопоточности из-за этого там не могло быть и речи, а следовательно никакие примитивы для синхронизации там были не нужны.