|
|
  |
Вопрос по volatile |
|
|
|
Jan 18 2017, 10:53
|
Профессионал
    
Группа: Свой
Сообщений: 1 468
Регистрация: 28-03-10
Из: Беларусь
Пользователь №: 56 256

|
jcxz, сейчас я тоже начну вас оскорблять  Изменять все переменные, используемые в прерывании, необходимо атомарно (или вы не в курсе?), и нам в принципе без разницы, куда компилятор запишет значение во время преобразований, хоть в регистр, хоть будет "держать в уме". Пока по прежнему нет реального примера, кроме блокирующих операций, где компилятор может сделать не так, как предполагалось. В статьях обычно об этом пишут как-то абстрактно, а никто детально не желает разобраться, как действительно все работает.
|
|
|
|
|
Jan 18 2017, 11:12
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Alt.F4 @ Jan 18 2017, 13:53)  jcxz, сейчас я тоже начну вас оскорблять  Изменять все переменные, используемые в прерывании, необходимо атомарно (если вы не в курсе), и нам в принципе без разницы, куда компилятор запишет значение во время преобразований, хоть в регистр, хоть будет "держать в уме". Да при чём тут атомарность-то??? Вы хотя-бы прочитали и поняли что я написал? Изменений переменной в фоновом программе может вообще не быть.
|
|
|
|
|
Jan 18 2017, 11:23
|
Профессионал
    
Группа: Свой
Сообщений: 1 214
Регистрация: 23-12-04
Пользователь №: 1 643

|
Приветствую! Цитата(Alt.F4 @ Jan 18 2017, 13:53)  Изменять все переменные, используемые в прерывании, необходимо атомарно (если вы не в курсе), и нам в принципе без разницы, куда компилятор запишет значение во время преобразований, хоть в регистр, хоть будет "держать в уме".
Пока по прежнему нет реального примера, кроме блокирующих операций, где компилятор может сделать не так, как предполагалось. В статьях обычно об этом пишут как-то абстрактно, а никто детально не желает разобраться, как действительно все работает. Volatile к атомарности никакого отношения не имеет! Volatile указывает компилятору что значение переменной может изменится ВНЕ текущего контекста зоны видимости переменной. Поэтому компилятор НЕ вправе оптимизировать ЧТЕНИЕ актуального состояния этой переменной. Пример Вам уже приводили - чтение переменной в цикле. И не только как блокировка, а например очень часто при опросе регистров состояния периферии, биты которых меняются аппаратно. Удачи! Rob.
|
|
|
|
|
Jan 18 2017, 11:24
|
Профессионал
    
Группа: Свой
Сообщений: 1 468
Регистрация: 28-03-10
Из: Беларусь
Пользователь №: 56 256

|
jcxz, читаю "на входе в эту функцию, компилятор вполне может переместить значение переменной в регистр" И каким боком из-за этого переменная может не изменяться вообще? В текущий момент пусть функция не видит изменения, при следующем входе снова прочитает по адресу и все увидит. Где проблема?
RobFPGA, об этом речи и не идет, атомарность делает сам программист, конечно. Ок, добавляем еще одну ситуацию, кроме блокирующих - чтение регистров ввода/вывода, хотя они уже по умолчанию идут как volatile, и программисту об этом не надо заботиться.
|
|
|
|
|
Jan 18 2017, 11:49
|
Профессионал
    
Группа: Свой
Сообщений: 1 214
Регистрация: 23-12-04
Пользователь №: 1 643

|
Приветствую! Цитата(Alt.F4 @ Jan 18 2017, 14:24)  jcxz, читаю "на входе в эту функцию, компилятор вполне может переместить значение переменной в регистр" И каким боком из-за этого переменная может не изменяться вообще? В текущий момент пусть функция не видит изменения, при следующем входе снова прочитает по адресу и все увидит. Где проблема?
RobFPGA, об этом речи и не идет, атомарность делает сам программист, конечно. Ок, добавляем еще одну ситуацию, кроме блокирующих - чтение регистров ввода/вывода, хотя они уже по умолчанию идут как volatile, и программисту об этом не надо заботиться. Это если за Вас уже позаботились сделав правильный BSP, а если эта периферия сидит например во внешней FPGA которая отмаплена на память? И не только регистры, а например буфера данных которые пишутся через DMA, а проц их только читает для обработки. И что с оптимизирует компилятор в этом случае если НИГДЕ в Вашей программе нет ЗАПИСИ в этот буфер/переменную? Удачи! Rob.
|
|
|
|
|
Jan 18 2017, 11:52
|

Просто Che
    
Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881

|
Цитата(Alt.F4 @ Jan 18 2017, 13:24)  jcxz, читаю "на входе в эту функцию, компилятор вполне может переместить значение переменной в регистр" И каким боком из-за этого переменная может не изменяться вообще? В текущий момент пусть функция не видит изменения, при следующем входе снова прочитает по адресу и все увидит. Где проблема? Если ваше прерывание будет только читать эту временно перемещенную переменную, то ничего не произойдет, она прочтет новое значение позже. А вот если прерывание тоже изменяет это значение, то это значение пропадет, так как функция при выходе сохранит в эту переменную свое значение. А если глобально про volatile, то я не слишком часто его применяю, только там, где вышеприведенные эффекты могут иметь место или есть опасность выкидывания компилятором моего кода. Обычно анализирую возможность поведения каждой переменной, и если гиблые состояния видны, применяю. А если простая передача данных по флагам из/в прерывания, то и так все работает.
|
|
|
|
|
Jan 18 2017, 12:33
|
Профессионал
    
Группа: Свой
Сообщений: 1 468
Регистрация: 28-03-10
Из: Беларусь
Пользователь №: 56 256

|
RobFPGA, думаю, если буфер объявлен глобально, то компилятор не вырежет код, даже если "НИГДЕ в Вашей программе нет ЗАПИСИ в этот буфер/переменную". Имхо, компилятор работает исключительно локально, относительно кода функции, и не проверяет, в каком месте и пишутся ли вообще данные в глобальные переменные. Цитата А вот если прерывание тоже изменяет это значение, то это значение пропадет, так как функция при выходе сохранит в эту переменную свое значение. Ну как бы изменения делаем атомарно, это уже обсудили.
|
|
|
|
|
Jan 18 2017, 13:54
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(Alt.F4 @ Jan 17 2017, 23:45)  RobFPGA, по идее вообще без разницы, где эта переменная будет изменяться, что-то мы ходим по кругу... Переменная не может где-то изменяться. Она находится всегда там, где определена изначально: глобальная - в памяти, регистровая - в регистре, временная в стеке. И только так. Никаких "путешествий" она не производит по стекам и регистрам она не производит: в стек и регистры компилятор записывает копии значения переменных. Компилятор производит компиляцию исходя из предположения по умолчанию, что копия значения переменной всегда тождественна оригинальному, и как раз служебное слово volatile говорит компилятору, что это не так и переменная может поменять свое значение в прерываниии.
Сообщение отредактировал aiwa - Jan 18 2017, 13:54
|
|
|
|
|
Jan 18 2017, 14:05
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Alt.F4 @ Jan 18 2017, 14:24)  И каким боком из-за этого переменная может не изменяться вообще? В текущий момент пусть функция не видит изменения, при следующем входе снова прочитает по адресу и все увидит. Где проблема? У меня возникает ощущение что Вы троллите всех тут.... Как можно не понимать очевидных вещей?? Пример (жизненный, написал специально для Вас): CODE enum {F_NONE, F_SLEEP_STATE, F_TIMER, F_SERVICE_REQUEST_1, F_SERVICE_REQUEST_2}; int flag = F_NONE; void f() { if (flag == F_NONE) { //ТОЧКА1 ENTR_CRT_SECTION(); //входим в критическую секцию (просто запрет прерывания) if (flag == F_NONE) { flag = F_SLEEP_STATE; EXIT_CRT_SECTION(); //покидаем критическую секцию Sleep(); } else EXIT_CRT_SECTION(); } int i = flag; flag = F_NONE; switch (flag) { case F_TIMER: return; case F_SERVICE_REQUEST_1: ... //обслуживание сервиса 1 break; case F_SERVICE_REQUEST_2: ... //обслуживание сервиса 2 break; } } void isr1() { PeripheralIntReqReset1(); if (flag == F_SLEEP_STATE) WakeUp(); else if (flag != F_NONE && flag != F_TIMER) return; flag = F_SERVICE_REQUEST_1; } void isr2() { PeripheralIntReqReset2(); if (flag == F_SLEEP_STATE) WakeUp(); else if (flag != F_NONE && flag != F_TIMER) return; flag = F_SERVICE_REQUEST_2; } void isrTimer() { if (flag == F_SLEEP_STATE) WakeUp(); else if (flag != F_NONE) return; flag = F_TIMER; } Теперь представьте что эта функция вызывается периодически (суперцикл или корпоративная многозадачность). Включена максимальная оптимизация и на входе в функцию f() при первом обращении компилятор перенёс переменную flag в регистр, а в месте ТОЧКА1 происходит какое-либо прерывание, которое пишет запрос обслуживания в flag. Так вот - при компиляции с макс. оптимизацией, этот код будет сбоить (терять запросы на обслуживание). Но если к определению flag добавить volatile, всё будет прекрасно работать с любым уровнем оптимизации. Чтобы пресечь возможные доводы типа "искусственный пример", допустим: isr1()/isr2() к примеру - это ISR-ы о готовности данных к чтению в FIFO-буфере некоей периферии, которая однократно выставляет флаг готовности при достижении некоего уровня заполнения FIFO. Эти данные надо считать. Причём считать до прихода след. данных чтобы избежать потерь. И можно 1000 подобных примеров придумать и с более сложными зависимостями. Цитата(Alt.F4 @ Jan 18 2017, 15:33)  думаю, если буфер объявлен глобально, то компилятор не вырежет код, даже если "НИГДЕ в Вашей программе нет ЗАПИСИ в этот буфер/переменную". Опять неправда. Если записи нет, а есть только чтения, то компилятор заменит все чтения этой переменной загрузкой константы в регистр. А потом компоновщик увидит, что к этой переменной нет ни одного обращения и удалит её за ненадобностью.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|