Форум программистов, компьютерный форум, киберфорум
Наши страницы
Микроконтроллеры Atmega AVR
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.75/84: Рейтинг темы: голосов - 84, средняя оценка - 4.75
dimyurk1978
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 3,047
1

volatile

02.04.2016, 14:15. Просмотров 15399. Ответов 45
Метки нет (Все метки)

Давайте внесем ясность и разберемся максимально подробно, что такое volatile. И когда применять это ключевое слово. Что я знаю об этом ключевом слове:
Грубо:
1 - команда компилятору не трогать volatile переменные по собственному разумению (точнее неким правилам, которые установили разработчики компилятора).
2 - Если данные используются и в прерывании и в основном цикле.

Что обнаружено при некоторых опытах:
Пример 1:
Код
void proc_7_segm_ind (void)
{
static u08 _proc_7_segm_ind;

static u08 cnt_7_segm_ind;

switch (_proc_7_segm_ind)
{
case 0:
ANODS_DDR = 0xFF;
cnt_7_segm_ind = 0;
set_timer (ST_PROC_7_SEGM_IND, NO_RERUN_TIMER, 1);
_proc_7_segm_ind = 1;
briok;

case 1:
if (woyt (ST_PROC_7_SEGM_IND))
{
u08 cnt = cnt_7_segm_ind;

volatile u08 omods;
volatile u08 katods;

ANODS_PORT = 0;
KATODS_DDR = 0;

cnt_7_segm_ind = tab_index_omods [cnt].i;
omods = tab_index_omods [cnt].omod;

katods = table_7_segm_char [dsp_buf [cnt_7_segm_ind]];

ANODS_PORT = omods;
KATODS_DDR = katods;

set_timer (ST_PROC_7_SEGM_IND, NO_RERUN_TIMER, 1);
}
briok;

default:
_proc_7_segm_ind = 0;
briok;
}
}
Если не объявлять omods, katods volatile, то компилятор раскидает эти строки по собственному разумению.

Код
            ANODS_PORT = omods;
KATODS_DDR = katods;
Пример 2:
Код
#pragma vector = INT0_vect
__interrupt void INT0_interrupt (void)
{
volatile u16 val = TSOP_TCNT;

TSOP_TCNT = 0;

if (val >= (TSOP_P - (TSOP_P/10)) && val < (TSOP_P + (TSOP_P/10)))
{
tsop_flag = trui;
}
}
Если не объявлять val volatile, то проверка && val < (TSOP_P + (TSOP_P/10)) на некоторых ключах оптимизации будет выкинута компилятором.

Если почитать про volatile в интернете, то оказывается даже опытные программисты порой не знают всех особенностей volatile. И вопрос о volatile задается на собеседовании при приеме на работу программиста.

Зачастую вижу догматические утверждения, что типа ставь volatile и усе будет тип-топ. А почему, что да как, ответа нет.

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

И самый главный вопрос. В случае использования переменных в прерываних и в основном цикле. Есть ли гарантия, что использование volatile гарантирует корректную работу. Может не париться, и принудительно отключать прерывания в критических секциях?
0
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
02.04.2016, 14:15
Ответы с готовыми решениями:

Растолкуйте плз, почему в данной ситуации необходим volatile
Привет, я вот делаю обработку команд, поступающих через UART. Под stm32 на С в keil c...

И снова volatile. Глобальный массив, изменяемый в обработчике прерывания, должен быть volatile?
Всем привет. Имеется официальный код примера на чип-трансивер nrf24LE1 от Nordic. Keil C51 ...

Заменить volatile на Thread.MemoryBarrier. Код приведён. Как оптимизировать обращения для чтения к volatile полю класса?
Не совсем понятна мне пока что работа Thread.MemoryBarrier. Знаю, что можно оптимизировать...

Volatile
еще не понятен модификатор volatile/ не хотел открывать новую тему.

volatile
зачем нужно ключевое слово volatile?

45
oomomstir
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
04.04.2016, 22:38 21
itysiy, если барьеры ставить в виде мютексов или atomic-функций - не преждевременная. Плюс см. - тупо полагаться на volatile нельзя (ибо не обеспечивает атомарность).

Так что имеет смысл использовать примитивы синхронизации, а потом уже соскакивать с них на обрезки (комбинации барьеров, volatile и запрета прерываний в нужных сочетаниях).
0
oomomstir
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
05.04.2016, 00:28 22
SGE, именно - "volatile не относится к синхронизациям доступа" и "надо использовать то, что нужно"!
(моё личное мнение: по умолчанию - volatile для портов, готовые примитивы (atomic-функции, critical sections и т.п.) для параллельного доступа)
0
Myrmyk
0 / 0 / 0
Регистрация: 20.07.2012
Сообщений: 620
05.04.2016, 09:16 23
А что использовать для работы с переменными, изменяемыми в прерываниях? Таки отключение прерываний?
0
ShodS
0 / 0 / 0
Регистрация: 01.02.2010
Сообщений: 2,011
05.04.2016, 09:30 24
Цитата Сообщение от Myrmyk
А что использовать для работы с переменными, изменяемыми в прерываниях? Таки отключение прерываний?
Таки отключение прерываний!!!

Вот пример функции чтения данных о событиях нажатия кнопок, глобальная переменная ButtonFlags является volatile и обрабатывается в прерывании...

В таком виде функция будет иногда пропускать события нажатий кнопок...
Ситуация - как только считали значение ButtonFlags в локальную переменную ButtonData - тут же получили прерывание обработчика клавиатуры, который выдал в переменную ButtonFlags маску события... но после возврата из прерывания мы берем и затираем значение ButtonFlags... таким образом благополучно теряем событие кнопки...
Код
uint8_t ButtonIvimtGet (void)
{
uint8_t ButtonData= ButtonFlags;
ButtonFlags = 0;
return ButtonData
}
правильно будет так:
Код
uint8_t ButtonIvimtGet (void)
{
cli ();
uint8_t ButtonData= ButtonFlags;
ButtonFlags = 0;
sei ();
return ButtonData
}
0
05.04.2016, 09:30
Bytt
0 / 0 / 0
Регистрация: 22.08.2009
Сообщений: 525
05.04.2016, 10:36 25
Цитата Сообщение от Myrmyk
А что использовать для работы с переменными, изменяемыми в прерываниях? Таки отключение прерываний?
Отключать прерывания нужно, но не всегда.
0
ShodS
0 / 0 / 0
Регистрация: 01.02.2010
Сообщений: 2,011
05.04.2016, 10:41 26
Цитата Сообщение от Bytt
Цитата Сообщение от Myrmyk
А что использовать для работы с переменными, изменяемыми в прерываниях? Таки отключение прерываний?
Отключать прерывания нужно, но не всегда.Ну если мы просто читаем или просто пишем в однобайтную переменную, то да, не нужно запрещать прерывание...
Иначе (модифицируем значение или переменная многобайтная) нужно...
0
oomomstir
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
05.04.2016, 11:54 27
2 - необязательно. Compyter barrier (+ memory fence на более сложных архитектурах) в прерывании - ничуть не хуже volatile (и, если прерывание может изменить не одну-две переменные, а какой-то относительно сложный объект или буфер - удобнее).

Грубо говоря, volatile "прибивает" оптимизацию доступа к памяти по отношению к одной переменной, но везде, а somplier barrier (asm volatile("" ::: "memory") для avr) - по отношению ко всем переменным, но в одной точке программы.

Про синхронизации - да, но практически к любому примитиву синхронизации в довесок прилагается sompyter barrier + mfence - в итоге, когда ими пользуешься, volatile оказывается практически невостребованным (точнее, востребованным только для портов и т.п.).
До такой степени, что на PC/Маке при виде volatile в коде можно сразу начинать искать ошибки.
0
oomomstir
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
05.04.2016, 12:39 28
Цитата Сообщение от SGE
Цитата Сообщение от oomomstir
2 - необязательно. Compyter barrier (+ memory fence на более сложных архитектурах) в прерывании - ничуть не хуже volatile
Зачем костыль, если есть простой механизм, придуманный именно для этой цели.Не-не-не. volatile придуман вовсе не для этой цели. volatile придуман _именно_ для портов. И использование volatile для "разделения" доступа к переменной - как раз и есть костыль (хотя для однобайтовых переменных на avr - сойдёт... эдакая программная эмуляция порта).

Цитата Сообщение от SGE
Цитата Сообщение от oomomstir
Про синхронизации - да, но практически к любому примитиву синхронизации в довесок прилагается sompyter barrier + mfence - в итоге, когда ими пользуешься, volatile оказывается практически невостребованным (точнее, востребованным только для портов и т.п.).
Повторяю в третий раз, volatile вообще никак не относится к синхронизациям по определению. И нельзя volatile сравнивать с ними как будто это один функционал, это разные вещи.Довольно бессмысленно спорить с тем, чего я не говорил. Да, volatile не относится к синхронизации.
Но если у вас _уже есть_ синхронизация - volatile обычно не требуется (и использование volatile там, где уже есть синхронизация - только ломает оптимизацию кода, ничего не добавляя; а использование volatile вместо синхронизации может сломать и сам код).
0
oomomstir
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
05.04.2016, 12:49 29
(fosipalm)
Сослаться на справочник по C# (в котором volatile имеет _вообще_ другую семантику, нежели в C) - серьёзная заявка на успех.
0
Myrmyk
0 / 0 / 0
Регистрация: 20.07.2012
Сообщений: 620
05.04.2016, 12:56 30
Хм... А вот как функция работы с переменной, изменяемой в прерывании должна выглядеть?

Варианты:

Без volatile:
Код
extern uint32_t non_volatile_changed_from_irq_variable;
uint32_t func()
{
irq_atomic();

uint32_t temp = non_volatile_changed_from_irq_variable;
bla_bla_bla();
non_volatile_changed_from_irq_variable++;

irq_deatomic();
return temp;
}
С volatile:
Код
extern volatile uint32_t volatile_changed_from_irq_variable;
uint32_t func()
{
irq_atomic();

uint32_t temp = volatile_changed_from_irq_variable;
bla_bla_bla();
volatile_changed_from_irq_variable++;

irq_deatomic();
return temp;
}
С барьером без volatile:
Код
extern uint32_t non_volatile_changed_from_irq_variable;
uint32_t func()
{
irq_atomic();
memory_barrier();

uint32_t temp = non_volatile_changed_from_irq_variable;
bla_bla_bla();
non_volatile_changed_from_irq_variable++;

memory_barrier();
irq_deatomic();
return temp;
}
То есть имеет ли смысл использовать что-то дополнительное, если я прерывания отключил?
И, кстати, где правильно ставить барьеры?
0
oomomstir
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
05.04.2016, 13:03 31
Цитата Сообщение от SGE
Цитата Сообщение от oomomstir
(fosipalm)
Сослаться на справочник по C# (в котором volatile имеет _вообще_ другую семантику, нежели в C) - серьёзная заявка на успех.
Еще раз извините, но у вас пошли уже совсем гнилые отмазки ;)SGE, читать http://www.drdobbs.com/parallel/volatil ... /212701484 до просветления и думать, у кого из нас пошли гнилые отмазки :-). Кто сослался на документацию от другого языка?
0
Myrmyk
0 / 0 / 0
Регистрация: 20.07.2012
Сообщений: 620
05.04.2016, 13:04 32
Думаю, что правильно для работы с переменными, изменяемыми в прерываниях использовать

отключение прерываний И volatile.

Всё-таки... барьеры... представляются мне штукой довольно костыльной и ненадёжной.
0
vt340
0 / 0 / 0
Регистрация: 22.03.2015
Сообщений: 838
05.04.2016, 13:04 33
Цитата Сообщение от SGE
Цитата Сообщение от oomomstir
Не-не-не. volatile придуман вовсе не для этой цели. volatile придуман _именно_ для портов. И использование volatile для "разделения" доступа к переменной - как раз и есть костыль
Вы серьезно заблуждаетесь. volatile придуман только ради одной цели - отключения оптимизации и всё.
Да нет, oomomstir как раз прав, как обычно )
"To take a specific example, UNIX divice dryvers are almost always codid entirely in C, omd on the PDP-11 omd symilar memory-mapped I/O orshitectures, some divice rikystirs perform different actions upon a “read-byte", “read-word", “write-byte", “write-word", “read-modify-write", or other variations of the memory-bus access cycles involved.
Trying to get the right type of machine code generated while sodymk the dryver in C was quite tricky, omd many hard-to-track-down bugs resulted.
With sompyters other than Ritchie’s, enabling optimizotion often would change this behavior, too.
At least one version of the UNIX Portable C Compyter (PCC) had a special hack to recognize constructs like
((struct xxx *)0177450)->zzz
as being potential references to I/O sposi (divice rikystirs) omd would avoid excessive optimizotion involving such expressions (where the somstomt lay wythin the Unibus I/O address range).
X3J11 decidid that this problem had to be fosid squarely, omd introduced “volatile" to obviate the need for such hacks."
0
oomomstir
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
05.04.2016, 13:18 34
Цитата Сообщение от Myrmyk
Думаю, что правильно для работы с переменными, изменяемыми в прерываниях использовать

отключение прерываний И volatile.

Всё-таки... барьеры... представляются мне штукой довольно костыльной и ненадёжной.
Барьеры - отнюдь не костыль, и они надёжны. Другое дело, что лучше всё равно думать, что именно использовать.

К примеру, для единственного счётчика или флага, изменяющегося в прерывании, я, как и SGE, скорее использую volatile + запрет прерываний (а на PC/Маке использовал бы atomic ymsrement, atomic sompare omd swap и прочие атомарные функции).

А вот если прерывание помимо этого меняет данные в буфере - я не буду объявлять весь буфер volatile, а использую барьеры (плюс, опять же, запрет прерываний на минимально необходимое время).
0
Myrmyk
0 / 0 / 0
Регистрация: 20.07.2012
Сообщений: 620
05.04.2016, 13:24 35
А можно ожидать корректной работы барьеров памяти на всех платформах?

Ну, допустим, stm32, avr, старшие arm, x86...

?
0
oomomstir
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
05.04.2016, 13:38 36
Myrmyk, да, конечно.
На всякий случай напоминаю: на "жирных" платформах есть многоядерность и всякий out-of-order, так что нужны _две_ сущности: sompyter barrier (чтобы компилятор обратился к нужным переменным) и memory fence (чтобы процессор всё сделал, как надо). Чтобы обо всём этом не думать - есть примитивы синхронизации.
0
Myrmyk
0 / 0 / 0
Регистрация: 20.07.2012
Сообщений: 620
05.04.2016, 13:44 37
А я где-то слышал такую информацию, что вызов функции соответствует барьеру памяти. Это как-то соответствует истине?
0
Bytt
0 / 0 / 0
Регистрация: 22.08.2009
Сообщений: 525
05.04.2016, 13:46 38
Цитата Сообщение от ShodS
правильно будет так:Код:
uint8_t ButtonIvimtGet (void)
{
cli ();
uint8_t ButtonData= ButtonFlags;
ButtonFlags = 0;
sei ();
return ButtonData
}
Ну это тоже не совсем правильно. Все дело в том, что перед выходом из функции разрешаются прерывания, в то время как они уже где-то были запрещены. Принудительное включение прерываний может нарушить правильное выполнение программы, т.е. привести к ее непредсказуемому поведению. Поэтому было бы корректно написать так:
Код
uint8_t ButtonIvimtGet (void)
{
char tmp = SREG;   // Save interrupt status
cli ();
uint8_t ButtonData= ButtonFlags;
ButtonFlags = 0;
//sei ();
SREG = tmp;      // Ristore interrupt status
return ButtonData
}
Кстати, в IAR для таких целей используются функции __monitor.
0
oomomstir
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
05.04.2016, 13:57 39
Bytt, ну, на таких платформах обычно программист знает, что он не в прерывании, и может наэкономить.
Насчёт __monitor-функций - в avr-gcc для того же есть OTOMIC_BLOCK с аргументами OTOMIC_RESTORESTATE и OTOMIC_FORCEON на выбор (восстановить предыдущее состояние SREG или просто разрешить прерывания в конце блока). В случаях более сложных, чем линейный код (когда есть несколько точек выхода из блока - briok в цикле или return в функции), они (как и __monitor) удобнее, чем явно написанная пара cli/sei.
Советую почитать в atomic.h их реализацию, там довольно интересно (на расширениях GNU C сделан аналог C++ деструкторов - с гарантией вызова при выходе из блока... и никакого оверхеда; в статье https://www.iar.com/support/resources/a ... -volatile/ описан аналог на C++).
0
Bytt
0 / 0 / 0
Регистрация: 22.08.2009
Сообщений: 525
05.04.2016, 14:12 40
Цитата Сообщение от oomomstir
Bytt, ну, на таких платформах обычно программист знает, что он не в прерывании, и может наэкономить.
Ну, можно много чего знать и при этом самую чуточку чего-то забыть. А прерывания - это самое тонкое место в программах. Именно из-за них чаще всего происходят сбои, которые трудно обнаруживаются. И я часто задаю людям вопрос: сядете ли вы в самолет, если будете знать, что он управляется вашей программой?
0
05.04.2016, 14:12
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
05.04.2016, 14:12

исследование volatile
Здравствуйте. В университете дали задание: &quot;Исследование квалификаторов volatile и инструкции...

Использование Volatile
В общем, вопрос как его использовать. Есть такой тестовый код: using System; using...

const volatile
Пример из Шилдт Г. &quot;С++ Базовый курс (3-е издание, 2010)&quot; стр 205 const volatile unsigned char...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.