Атомарный доступ к переменным |
Написал microsin | |
02.07.2010 | |
При отладке встраиваемых приложений, наиболее сложно отловить ошибки, проявляющие себя не постоянно, а лишь время от времени. Одна из причин подобных багов: переменные, доступ к которым осуществляется асинхронно. Такие переменные должны быть правильно определены, и иметь соответствующую защиту. Определение должно включать ключевое слово volatile. Оно информирует компилятор, о том, что переменная может быть изменена не только из текущего выполняемого кода, но и из других мест. Тогда компилятор будет избегать определенных оптимизаций этой переменной. Чтобы защитить общую переменную, каждая операция доступа к ней должна быть атомарной. То есть не должна прерываться до своего окончания. Например, доступ к 32 или 16 разрядной переменной на 8-ми разрядной архитектуре не атомарный, поскольку операции чтения или записи требуют больше одной инструкции.
Рассмотрим типичный пример
общедоступной переменной – программный таймер. В обработчике прерывания
его значение изменяется, а в основном коде - считывается. Если в
обработчике другие прерывания запрещены, как, например, по дефолту
сделано в микроконтроллерах AVR, то операция изменения переменной
атомарна и никаких косяков не случится.
Если
требуется, чтобы прерывания запрещались в каком-то конкретном участке
кода, можно использовать intrinsic функции. Вообщем принцип везде один, а вариантов реализации много. Можно, например, при доступе к переменной запрещать не все прерывания, а только те, в которых используется эта переменная. Проблема возможна и с восьмибитной переменной. Операция вроде system_timer -= 100 компилится в несколько ассемблерных инструкций и в основном коде также может быть прервана между чтением system_timer и записью результата. Есть еще один способ чтения многобайтовых асинхронных счетчиков (без запрета прерываний) - считать переменную два раза и сравнить все байты кроме младшего. Если байты в копиях равны - берем последнее считанное значение, если не равны - считываем до тех пор, пока в двух последних считанных значениях байты не будут равны. Младший байт счетчика между чтениями может успеть измениться без переноса, поэтому он в проверке не участвует.
Как видно из примеров, код приведен для компилятора IAR. В WinAVR
подобная проблема решается включением файла , в котором определены
макросы для реализации атомарного доступа.
#include <util/atomic.h> Статья взята с http://chipenable.ru/index.php/programming-c/16-volatile-critical-section.html. |
|
Последнее обновление ( 07.07.2010 ) |