Перейти к содержанию
    

Ну как бы изменения делаем атомарно, это уже обсудили.

Ну как бы вам уже несколько человек на пальцах объяснили, что атомарность тут не причем :)

Попробую еще раз:

Если глобальная переменная не объявлена volatile, то ваша функция из главного цикла, работая с этой переменной,

имеет право (но не обязана) поместить её копию в регистр или в стек.

И внутри функции работать с этой копией (атомарно или как хочет) согласно вашей программы.

И только при выходе из функции записать эту копию в основное глобальное место.

Т.е. во время работы функции могут быть две копии (и различные!).

 

Прерывания этого не знают и работают с переменной из глобальной памяти.

И функция при выходе результат работы прерывания затирает.

 

А если объявить эту глобальную переменную volatile, то компилятору будет запрещено делать копии и работать с ними.

Все изменения этой переменной будут происходить только по основному месту хранения.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Господа никогда не понимал таких споров. Процесс важен или результат? Сюрпризы возможны, не проще ли дать volatile и забыть?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

Ну как бы вам уже несколько человек на пальцах объяснили, что атомарность тут не причем :)

...

Если глобальная переменная не объявлена volatile, то ваша функция из главного цикла, работая с этой переменной,

имеет право (но не обязана) поместить её копию в регистр или в стек.

И внутри функции работать с этой копией (атомарно или как хочет) согласно вашей программы.

И только при выходе из функции записать эту копию в основное глобальное место.

Т.е. во время работы функции могут быть две копии (и различные!).

 

Прерывания этого не знают и работают с переменной из глобальной памяти.

И функция при выходе результат работы прерывания затирает.

 

А если объявить эту глобальную переменную volatile, то компилятору будет запрещено делать копии и работать с ними.

Все изменения этой переменной будут происходить только по основному месту хранения.

Простите но это фигня "... а не заливная рыба ..." :wacko: Вы тоже путаете атомарность и Volatile.

Глобальная переменная может быт считана в регистр для работы с ней, но копироваться при этом в стек она не будет.

 

Еще раз "Volatile указывает компилятору что значение переменной может изменится ВНЕ текущего контекста зоны видимости переменной"

Другими словами - меняет правило расчета "срока жизни" переменной в текущем контексте кода.

Это значит что если в текущем контексте функции/таска/isr требуется несколько чтений из переменной то ВСЕ они БУДУТ РЕАЛЬНО выполнены из актуального местоположения переменной. И не важно - будет ли изменятся или нет переменная этом контексте.

Например если var не volatile и Вы хотите:

   sum += var;
  sum += var;

компилятор может сделать одно чтение var затем умножение на 2 и сложение с sum так как срок жизни переменной не заканчивается

если будет volatile - то ВСЕГДА будет 2 чтения из памяти.

 

Вот еще пример - иногда требуется только сам факт чтения/записи переменной (без реальных значений) для выполнения какого либо действия в периферии. Без volatile такое "бессмысленное расточительство" режется на корню "слишком умным" компилятором.

 

Удачи! Rob.

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Атомарность тут не при чём.

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

Если переменная не объявлена как регистЕр, то никуда компилятор её не перенесёт. Не вводите людей в заблуждение.

 

А если я работаю с переменной через указатель на неё, то что?

Я должен такую переменную объявлять как волатайл?

 

Компилятор (и примкнувший к нему линкер) вообще ничего не знают про прерывания. Есть только функции, расположенные по определенным адресам. А то, что эти функции могут обрабатывать прерывания, и прерывать другие функции в любом месте, знает только разработчик на основе архитектуры контроллера, под который он пишет программу.

А в вашем примере и volatile не спасет, так как суммирование x и чисел N1,N2,N3 неатомарно.

Есть такая штука, называется "сохранение контекста прерванной задачи".

Хотя конечно есть двухбайтовые команды работы напрямую с РВВ, обращение к которым должно происходить в соседних тактах процессора.

Тогда ой. Нужно запрещать прерывания перед такой критической последовательностью команд.

Иначе вообше может произойти катастрофа если прерывание разорвет двухбайтовую последовательность команд

 

jcxz, вот именное такие: "например можете в цикле ждать когда установится некий флажок" (цитирую Вас же).

 

RobFPGA, по идее вообще без разницы, где эта переменная будет изменяться, что-то мы ходим по кругу...

 

Проблема: компилятор оптимизируя вырезает кусок кода считая его лишним.

На основании чего он это делает? Он знает, что некая переменная имеет в текущий момент определенное состояние.

Значит, если на входе функции мы не присваиваем ей какое либо значение и затем не проверяем эту переменную на другие значения (что для компилятора кажется безумным и он это режет), то и volatile не нужен.

Именно так. Именно для этого введен волатйл. Чтобы запретить компилятору "оптимизировать" (чаще всего просто удалять) куски кода, которые содержат якобы не изменяемые и не используемые переменные

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Простите но это фигня "... а не заливная рыба ..." :wacko: Вы тоже путаете атомарность и Volatile.

Ничего не имею против ваших разъяснений работы volatile, но доводов того, что "моя заливная рыба" это фигня, я у вас не нашел. :laughing:

 

Атомарность это запрещение различных прерываний, исключений, переключения задач и т.д. на каком-то участке кода.

Это никак не запрещает компилятору в функции работать с переменной атомарно, но при этом работать с её копией.

 

Глобальная переменная может быт считана в регистр для работы с ней, но копироваться при этом в стек она не будет.

Для простых систем, где память переменных и стек находятся в равнозначной памяти - не будет.

Но бывают и другие виды памяти, доступ к которым различен по времени. Вот в этом случае такое вполне возможно.

 

Господа никогда не понимал таких споров. Процесс важен или результат?

Для достижения желаемого результата неплохо бы разбираться в особенностях процесса :rolleyes:

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если переменная не объявлена как регистЕр, то никуда компилятор её не перенесёт.

Вы, как обычно, совершенно ничего не смыслите в том, о чем пытаетесь писать. Разумеется компилятор может и делает это. Да и квалификатор register уже давно у большинства компиляторов просто игнорируется.

Не вводите людей в заблуждение.

Это по Вас.

Именно для этого введен волатйл. Чтобы запретить компилятору "оптимизировать" (чаще всего просто удалять) куски кода, которые содержат якобы не изменяемые и не используемые переменные

Опять ерунда - оптимизировать работу с переменной volatile не запрещает. Оптимизация, неизменяемость и неиспользование это три разных понятия. Кроме них еще есть одно важное понятие - обращение к переменной.

 

 

Атомарность это запрещение различных прерываний, исключений, переключения задач и т.д. на каком-то участке кода.

Никак нет. То, что описали, это критическая секция, точнее один из вариантов ее реализации.

Соответственно и все, что дальше написали это не о чем :(

 

 

А если объявить эту глобальную переменную volatile, то компилятору будет запрещено делать копии и работать с ними.

Все изменения этой переменной будут происходить только по основному месту хранения.

Расскажите это создателям ARM ядра и множества других с Load-Store :). Они просто не умеют, так, как Вы представляете.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Никак нет. То, что описали, это критическая секция, точнее один из вариантов ее реализации.

Соответственно и все, что дальше написали это не о чем :(

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

 

Расскажите это создателям ARM ядра и множества других с Load-Store :). Они просто не умеют, так, как Вы представляете.

Наверно, здесь был не точен. Конечно, volatile не создаст атомарный доступ к переменной, но хотя бы предотвратит создание компилятором её "долгоживущих" копий.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если я работаю с переменной через указатель на неё, то что?

Я должен такую переменную объявлять как волатайл?

 

Ведь компилятор не может проследить все случаи где я получаю доступ к переменной через указатель на неё

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если я работаю с переменной через указатель на неё, то что?

Я должен такую переменную объявлять как волатайл?

Правила те же: указатель должен быть объявлен как указатель на volatile-переменную.

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

 

 

Господа никогда не понимал таких споров. Процесс важен или результат? Сюрпризы возможны, не проще ли дать volatile и забыть?

"Споры" нужны для того, чтобы понять при каких ситуациях "сюрпризы возможны".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Правила те же: указатель должен быть объявлен как указатель на volatile-переменную.

А сама переменная?

Сама переменная должна объявляться как волатАЙл если её используют через указатель?

Что-то то я не видел в реальном коде разных разработчиков этого

 

Причем используют неявно. Без использования операции "взятие адреса" (амперсанд)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А сама переменная?

Сама переменная должна объявляться как волатАЙл если её используют через указатель?

Нет. Компилятор вещь достаточно умная - он понимает что такое указатель и к чему может привести взятие адреса переменной (для этой переменной)

Он даже понимает кое что в том, куда этот указатель может указывать - см ключевое слово restrict и опцию ansi alias ( http://www.atmos.washington.edu/~ovens/ifo...nsi_alias_f.htm )

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

jcxz, а мне Ваши примеры напоминают троллинг, повторение описанного ранее.

Я не вижу причин для сбоя в Вашем коде. В описанной ситуации функция не увидит возведение флажка, при втором входе в функцию все будет Ок. Повторюсь: где проблема?

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

 

Если записи нет, а есть только чтения, то компилятор заменит все чтения этой переменной загрузкой константы в регистр.

А потом компоновщик увидит, что к этой переменной нет ни одного обращения и удалит её за ненадобностью.

Какой еще константы, если она переменная? Как это нет обращения, Вы же ее читаете.

 

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

 

Вот еще пример - иногда требуется только сам факт чтения/записи переменной (без реальных значений) для выполнения какого либо действия в периферии. Без volatile такое "бессмысленное расточительство" режется на корню "слишком умным" компилятором.
Хороший пример, добавляем в копилку. Хотя можно объявить переменную глобально или extern, тоже будет работать.

 

"Споры" нужны для того, чтобы понять при каких ситуациях "сюрпризы возможны".

Пока имеем следующие ситуации требущие объявления volatile:

1) Переменные в блокирующих операций (ожидание определенного значения в цикле)

2) Все системные регистры, в том числе ввода/вывода (хотя они де-факто volatile)

3) Переменные в которые "просто читаем" из какого-либо регистра (как вариант, используем глобальную или extern переменную)

 

Еще пару примеров и можно делать мини-FAQ по теме вопроса :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

jcxz, а мне Ваши примеры напоминают троллинг, повторение описанного ранее.

Я не вижу причин для сбоя в Вашем коде. В описанной ситуации функция не увидит возведение флажка, при втором входе в функцию все будет Ок. Повторюсь: где проблема?

Очевидно что Вы и читать исходники не умеете. Посмотрите ещё раз на тот код. Вы ничего не поняли.

Я там вроде всё предельно разжевал, дальше некуда.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Пока имеем следующие ситуации требущие объявления volatile:
Не надо изобретать велосипед. Есть два критения:

1) если переменная используется в двух потоках (читай - в основном цикле и прерывании). Компилятор обязан при каждом обращении на чтение вычитывать ее из ОЗУ и при каждом обращении на запись класть обратно.

2) если важен порядок доступа к этой переменной (читай - регистры периферии). Компилятор обязан делать то же самое, что и п.1, кроме этого не имеет права менять местами обращения к этой переменной относительно обращений к другим volatile.

 

Сама переменная должна объявляться как волатАЙл если её используют через указатель?
Какая разница, как к ней обращаются? Если она попадает под указзанные выше два критерия - должна быть volatile. Все. И указатель должен иметь тип "указатель на volatile". Зачем так сделано - подумайте самостоятельно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Специально для Вас разжёвываю: функционал isr1 и isr2 взаимосвязан - если произошло одно, то выставление второго не нужно и даже запрещено (нужно знать какое было первое). И процедура сервиса, будучи запущенной, проверит и обслужит события.

Если совсем уже до детского уровня разжевать, например: это прерывания от двух счётчиков, запущенных от одного события, считающих с разной частотой, кто досчитает первым - тот и должен послать Int. Процедуре сервиса важно знать кто был первый, но обработка - общая.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...