Здравствуйте, Sinclair, Вы писали:
_>>А я нигде и не говорил о многозадачности/многопоточности. Я говорил о важности модификатора volatile для низкоуровневого программирования.
S>Ну вот это вот — типичная подмена понятий. Изначально делалось сильное утверждение про то, что volatile появился в C ради поддержки многозадачных ОС, которые и были его основным применением.
Кем и где делалось такое дикое утверждение? ) Я в любом случае подобного никогда не утверждал. И что-то сомневаюсь, что бы vdimas такое говорил, потому что, как это модно теперь здесь говорить, это был бы слишком большой залёт. )))
S>А теперь мы видим, что единственное приличное применение volatile — это memory-mapped HW, которое строго ортогонально многозадачности оси.
Ты не совсем правильно понимаешь. Применение volatile ортогонально и многозадачности и memory-mapped и вообще чему-либо "реальному". Это исключительно внутреннее дело компилятора C/C++, которому разрешают или не разрешают определённые вольности при генерации кода. Применяться это может в очень разных местах. И при работе с периферией процессора и при организации оптимизированных спинлоков (см. конец сообщения) в многопоточности и ещё много где.
S>Даже во вполне однозадачной ОС уровня MS-DOS работа с регистрами оборудования, отображёнными в память, будет требовать volatile, и, если я правильно понимаю принцип барьеров, то они тут неприменимы.
Да, всё правильно.
_>>Да, это именно задержка. И вполне себе надёжная. Т.е. понятно что аппаратный таймер лучше, но не во всех случаях его можно применить.
S>Нет, это ненадёжная задержка. Впендюрив сюда volatile, программист запрещает "устраняющие" оптимизации компилятору.
S>Но, во-первых, это никак не влияет на выбор размещения переменной, поэтому величина задержки получается произвольной даже в пределах одной аппаратуры — то ли будет выполнен сброс в память, то ли обойдёмся регистром. Какова будет разница в величине задержки?
S>Во-вторых, даже в пределах одной аппаратуры у нас может плавать тактовая частота, и скорость исполнения этого цикла будет меняться в разы.
S>Во-третьих, нет никакой гарантии, что во время цикла не будет выполнено вытеснение. Тогда можно запросто получить задержку на порядки больше, чем ожидалось.
Всё, что ты тут написал может быть справедливо например для написания ОС, но скажем для написания драйвера мотора на конкретном МК, это уже не актуально. )))
_>>Для полноценного спинлока тебе не хватит ни volatile, ни fences. Для него необходимы уже атомарные операции типа CAS или аналоги, поддерживаемые процессором.
S>Ну, тут мне не хватает квалификации для полноценного разговора. В рамках нашей дискуссии достаточно сказать, что volatile для спинлока бесполезен.
Нуу всё относительно.
Смотри, спинлок — это по сути почти такой же код, как в моём первом примере на тему volatile, только он после изменения ячейки памяти (и окончания блокировки) должен мгновенно вернуть старое значение в ячейку — осуществить захват ресурса. Точнее слово "мгновенно" тут даже не верно: проверка флага и его установка (в случае нулевого значения) должна происходить атомарно! И соответственно для возможности реализации такого кода, нужна соответствующая поддержка от процессора. Обычно это реализуется через атомарную инструкцию CAS (CMPXCHG для х86, доступна в C++ через эту
https://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange функцию класса atomic), которая как раз создана для таких целей и является базовым кирпичиком практически всех lock-free алгоритмов.
Казалось бы при применение CAS никакие volatile не нужны, достаточно только наличие у железа подобной инструкции. Но есть нюансы! ))) Инструкция CAS, как и все атомарные инструкции типа "прочитать-изменить-записать", весьма медленная. Поэтому частенько делают более интеллектуальную схему реализации спинлока: вставляют дополнительный блокирующий цикл ожидания, на обычном быстром чтение памяти (в точности как мой первый пример), а уже после его "прохода" реализуют захват на медленной атомарной функции. Ну и соответственно для возможности написания такой оптимизации, тебе очевидно потребуется volatile.
Вообще довольно иронично тут получается — для возможности оптимизации, тебе необходима возможность отмены другой оптимизации. )))