Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 31.12.21 13:26
Оценка:
Пытаюсь компилировать код, отлаженный под компиляторами MS VC++ 15.xx, компиляторами из новых студий (19.xx). В коде есть несколько классов, содержащих volatile-переменные. На них выдаются предупреждения:

warning C5220: 'Class::Var': a non-static data member with a volatile qualified type no longer implies that compiler generated copy/move constructors and copy/move assignment operators are not trivial... to simplify migration, consider the temporary use of /Wv:18 flag with the version of the compiler with which you used to build without warnings


Этим классам вообще не нужны ни конструкторы копирования/перемещения, ни операторы присваивания. Объявил фиктивные конструктор и оператор присваивания, как я это всегда делал для классов с const-членами — не помогло.

От этого можно как-то избавиться, кроме как принудительно запретить эти предупреждения? Вообще, что за "нетривиальность" оно имеет в виду?

В плане доступа/синхронизации с этими переменными все корректно, я просто хочу быть уверен, что компилятор нигде не сунет переменную в регистр, и не уберет операции чтения из памяти.
volatile c5220 trivial
Re: Volatile и предупреждение C5220
От: ArtDenis Россия  
Дата: 31.12.21 13:43
Оценка: 1 (1) +2
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Пытаюсь компилировать код, отлаженный под компиляторами MS VC++ 15.xx, компиляторами из новых студий (19.xx). В коде есть несколько классов, содержащих volatile-переменные.


Самое главное — не приводи минимальный код для воспроизведения, а то быстро ответят
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[2]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 31.12.21 14:03
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Самое главное — не приводи минимальный код для воспроизведения, а то быстро ответят


А смысл в таком коде? Тот, кто не знает про конкретно это предупреждение, по коду сможет сделать только предположения, а это я и сам могу.
Re: Volatile и предупреждение C5220
От: σ  
Дата: 31.12.21 14:06
Оценка:
ЕМ>Вообще, что за "нетривиальность" оно имеет в виду?
Какие кроме https://timsong-cpp.github.io/cppwp/n4868/class.copy.ctor#11 и https://timsong-cpp.github.io/cppwp/n4868/class.copy.assign#9 у тебя ещё есть варианты?
Отредактировано 31.12.2021 14:09 σ . Предыдущая версия .
Re[3]: Volatile и предупреждение C5220
От: ArtDenis Россия  
Дата: 31.12.21 14:28
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>А смысл в таком коде? Тот, кто не знает про конкретно это предупреждение, по коду сможет сделать только предположения, а это я и сам могу.


Да я не настаиваю )
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[2]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 31.12.21 15:10
Оценка:
Здравствуйте, σ, Вы писали:

ЕМ>>Вообще, что за "нетривиальность" оно имеет в виду?


σ>Какие кроме https://timsong-cpp.github.io/cppwp/n4868/class.copy.ctor#11 и https://timsong-cpp.github.io/cppwp/n4868/class.copy.assign#9 у тебя ещё есть варианты?


Я не о том, что конструктор/оператор, сгенерированный компилятором, будет считаться нетривиальным, а о том, что компилятор мог бы там в действительности сгенерить, чтобы оправдать это. Традиционно он генерит пустой конструктор, и оператор присваивания, побайтно копирующий объект. Что "нетривиального" он мог бы сам сгенерить для класса, содержащего volatile-переменную?

Или речь лишь о том, чтобы не допустить копирования/перемещения таких объектов, кроме как через явно определенные в классе средства? Если так, то каким образом запретить это явно, кроме добавления "=delete"? Мне нужно, чтоб код соответствовал и стандарту C++03, не хотелось бы городить там лишних условностей.
Re[3]: Volatile и предупреждение C5220
От: SaZ  
Дата: 02.01.22 14:57
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Или речь лишь о том, чтобы не допустить копирования/перемещения таких объектов, кроме как через явно определенные в классе средства? Если так, то каким образом запретить это явно, кроме добавления "=delete"? Мне нужно, чтоб код соответствовал и стандарту C++03, не хотелось бы городить там лишних условностей.


Можно явно указать стандарт в параметрах сборки. А если хотите код, который поддерживается не только С++03, то извольте городить макросы для условной компиляции. В бусте такого добра хватает.
Re[4]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 02.01.22 16:37
Оценка:
Здравствуйте, SaZ, Вы писали:

SaZ>Можно явно указать стандарт в параметрах сборки.


Я б с радостью, но VC++ не умеет ниже C++14.

SaZ>А если хотите код, который поддерживается не только С++03, то извольте городить макросы для условной компиляции.


Мне пока более всего интересно, в чем может заключаться фактическая нетривиальность конструктора и/или оператора присваивания, которые мог бы сгенерить компилятор по новому стандарту. Вы об этом что-нибудь знаете?
Re: Volatile и предупреждение C5220
От: _NN_ www.nemerleweb.com
Дата: 02.01.22 17:25
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>

ЕМ>warning C5220: 'Class::Var': a non-static data member with a volatile qualified type no longer implies that compiler generated copy/move constructors and copy/move assignment operators are not trivial... to simplify migration, consider the temporary use of /Wv:18 flag with the version of the compiler with which you used to build without warnings


Насколько я понимаю это просто предупреждение, что нужно понимать, что делаешь.
Судя по Trivial copy/move constructor for class with volatile member и P1153R0 — Copying volatile subobjects is not trivial решение будет ли тривиальным копирование или нет менялось туда и обратно с течением времени.
Если вы уверены в том, что реально происходит, просто проигнорируйте предупреждение.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Volatile и предупреждение C5220
От: Максим Россия  
Дата: 03.01.22 08:36
Оценка:
ЕМ>В коде есть несколько классов, содержащих volatile-переменные. На них выдаются предупреждения:

Если не секрет, зачем понадобились volatile-переменные? Какое-то устройство "замаплено" в память и нужно чтобы компилятор не с оптимизировал обращения к этой памяти?
Errare humanum est
Re[2]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 03.01.22 10:00
Оценка:
Здравствуйте, Максим, Вы писали:

М>зачем понадобились volatile-переменные?


Для реализации некоторых легковесных методов синхронизации. Например, там, где циклически выполняется группа операций, и этот цикл нужно останавливать по внешнему сигналу. Использовать там средства ОС избыточно — по уши хватит и volatile-переменных.
Re: Volatile и предупреждение C5220
От: reversecode google
Дата: 03.01.22 10:16
Оценка:
использовать атомики с релакс семантикой, а не заниматься анонизмом
Re[3]: Volatile и предупреждение C5220
От: reversecode google
Дата: 03.01.22 10:18
Оценка:
что за чушь ?
Re[3]: Volatile и предупреждение C5220
От: Максим Россия  
Дата: 03.01.22 11:05
Оценка: +3
ЕМ>Для реализации некоторых легковесных методов синхронизации. Например, там, где циклически выполняется группа операций, и этот цикл нужно останавливать по внешнему сигналу. Использовать там средства ОС избыточно — по уши хватит и volatile-переменных.

Мне кажется, Евгений, что так делать не стоит, volatile не гарантирует синхронизацию общих данных. Лучше использовать гарантированно lock-free на любых платформах std::atomic_flag. https://en.cppreference.com/w/cpp/atomic/atomic_flag
Errare humanum est
Отредактировано 03.01.2022 11:06 Максим . Предыдущая версия .
Re[4]: Volatile и предупреждение C5220
От: reversecode google
Дата: 03.01.22 11:09
Оценка: :))
ранее выяснили что он знает только c++98
атомики сильно сложно будет для него

к тому же он хочет обратной совместимости для c++98
что бы и для win3.11 можно было сбилдить
и продать исходники клиенту из прошлого, который на машине времени переместится в настоящее
Re[4]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 03.01.22 11:54
Оценка:
Здравствуйте, Максим, Вы писали:

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


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

М>Лучше использовать гарантированно lock-free на любых платформах std::atomic_flag


Мне пока не актуальны платформы, отличные от x86/x64, даже ARM под большим вопросом. Ну и не люблю я библиотечных конструкций в ядерном коде — они то реализованы "с особенностями", то тянут за собой лишний код из CRT, то не реализованы вообще.
Re[5]: Volatile и предупреждение C5220
От: Максим Россия  
Дата: 03.01.22 12:10
Оценка:
ЕМ>volatile должно гарантировать отсутствие буферизации, добавляемой компилятором. Если я, в свою очередь, гарантирую запись изменений в память параллельным потоком, то что может помешать считыванию измененных значений?

Volatile accesses cannot be optimized out or reordered ... This makes volatile objects suitable for communication with a signal handler, but not with another thread of execution, see std::memory_order.

https://en.cppreference.com/w/cpp/language/cv

Другими словами, можно ожидать, что компилятор просто так не выкинет volatile объекты, но нельзя расчитывать, что значения какой-то конкретной пременной в коде (например флага, котрый используется для остановки цикла) будут одинаковы для разных CPU.
Вот, кстати, неплохая статья с описанием того, где может пригодиться volatile https://habr.com/ru/company/abbyy/blog/161607/

ЕМ>Ну и не люблю я библиотечных конструкций в ядерном коде — они то реализованы "с особенностями", то тянут за собой лишний код из CRT, то не реализованы вообще.

Вы в ядре программируете? Там ведь свой набор примитивов синхронизации.
Errare humanum est
Отредактировано 03.01.2022 12:15 Максим . Предыдущая версия .
Re[6]: Volatile и предупреждение C5220
От: reversecode google
Дата: 03.01.22 12:21
Оценка: :)))

вы что вчера на форуме ?
Евгению все равно на ваши советы
он будет находить любые доводы почему ему это не подходит

просто ему во франции скучно,а из окружения только жена и дети
вот он и находит такую отдушину на форуме
для "поговорить ни о чем", но типа "на тему программирования"
Re[6]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 03.01.22 12:21
Оценка:
Здравствуйте, Максим, Вы писали:

М>Другими словами, можно ожидать, что компилятор просто так не выкинет volatile объекты, но нельзя расчитывать, что значения какой-то конкретной пременной в коде (например флага, котрый используется для остановки цикла) будут одинаковы для разных cpu.


Эти рассуждения годятся для программирования на C++ в стиле каких-нибудь Python или JS, где программа имеет дело с абстрактной виртуальной средой. Я программирую не для сферического железа в вакууме, в расчете на гипотетические платформы, а для вполне конкретного. Поэтому мне интересно, в каких конкретно случаях "нельзя рассчитывать", и почему. Вам известны такие сценарии?

М>Вы в ядре программируете? Там ведь свой набор примитивов синхронизации.


Не вижу смысла дергать примитивы, когда можно обойтись без них.
Re[7]: Volatile и предупреждение C5220
От: Максим Россия  
Дата: 03.01.22 12:31
Оценка:
ЕМ>Вам известны такие сценарии?

Ну так да. Самый простой сценарий. Есть пременная flag которая в одном потоке читается, что-то в духе
while(flag) {...}

а во втором изменяется
flag = false


Так вот, изменяя переменную во втором потоке, мы не знаем когда эти изменения "прилетят" в первый поток. Все зависит от того, где находится эта самая переменная, когда будут сброшены процессорные кеши итд.
Errare humanum est
Отредактировано 03.01.2022 12:33 Максим . Предыдущая версия .
Re[8]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 03.01.22 12:50
Оценка:
Здравствуйте, Максим, Вы писали:

М>Все зависит от того, где находится эта самая переменная


Так я и хочу с помощью volatile обеспечить ее нахождение в памяти, с возможностью буферизации на регистрах лишь на разумное время — например, в рамках вычисления выражения, в которое она входит. Это возможно, или с нынешней модой на абстракции уже и это не гарантируется?

М>когда будут сброшены процессорные кеши


За это отвечает код, изменяющий переменную.

М>итд.


А какие еще ситуации могут быть? Реальные, а не на гипотетическом железе будущего.
Re[9]: Volatile и предупреждение C5220
От: Максим Россия  
Дата: 03.01.22 13:03
Оценка: +1 -1
ЕМ>За это отвечает код, изменяющий переменную.

Нет, выставляя значение переменной вы просто меняете "локальную" копию этой переменной. Больше никаких гарантий нет (на системах где есть больше одного ядра). Чтобы эти изменения "прилетели" в другие потоки, нужны специальные процессорные инструкции которые будут добавлены компиляторм только в случае явного использования синхронизационных механизмов (volatile не входит в их число)
Errare humanum est
Re[10]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 03.01.22 13:08
Оценка:
Здравствуйте, Максим, Вы писали:

М>выставляя значение переменной вы просто меняете "локальную" копию этой переменной.


Вы действительно принимаете меня за идиота, или придуряетесь?

М>Чтобы эти изменения "прилетели" в другие потоки, нужны специальные процессорные инструкции которые будут добавлены компиляторм только в случае явного использования синхронизационных механизмов


Фраза "за это отвечает код" подразумевает, что код использует необходимые механизмы, явно или неявно.
Re[11]: Volatile и предупреждение C5220
От: Максим Россия  
Дата: 03.01.22 13:14
Оценка:
ЕМ>Фраза "за это отвечает код" подразумевает, что код использует необходимые механизмы, явно или неявно.
Я никак не могу понять, что конкретно вы делаете для этого? Если это volatile, то это не синхронизация от слова совсем. Можете показать примерный код?
Errare humanum est
Re[12]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 03.01.22 13:46
Оценка:
Здравствуйте, Максим, Вы писали:

М>что конкретно вы делаете для этого?


На платформах x86/x64 — ничего не делаю, ибо не требуется. Переносить код на другие платформы пока не планирую. Если встанет такой вопрос — сделаю то, что требуется там.

Напомню, вопрос возник потому, что компилятор предупреждает не о недостаточности volatile для синхронизации, а о "нетривиальности" автоматически генерируемого конструктора класса, содержащего volatile-переменную.

М>Можете показать примерный код?


class C {

  int volatile i;

};
Re[3]: Volatile и предупреждение C5220
От: fk0 Россия https://fk0.name
Дата: 03.01.22 13:53
Оценка: +1 -1
Здравствуйте, Евгений Музыченко, Вы писали:

М>>зачем понадобились volatile-переменные?


ЕМ>Для реализации некоторых легковесных методов синхронизации. Например, там, где циклически выполняется группа операций, и этот цикл нужно останавливать по внешнему сигналу. Использовать там средства ОС избыточно — по уши хватит и volatile-переменных.


OMG! Полярный песец!

Volatile не является барьером. Не атомарно. И из него никаких толком алгоритмов не построить, даже
алгоритм Петерсона требует чтоб число записывалось за один раз, атомарно.

И самое поганое, запись в volatile-переменные не упорядочена по сравнению с другими обращениями
к памяти. Компилятор может тебе сделать запись в volatile... Знаешь как? Вынести из цикла все такие записи
куда-нибудь в конец функции и выполнив там их оптом. Так оптимальней (реальная история, встретился на MIPS
на GCC 6-й версии). Нужен компиляторный барьер (роль которого впрочем выполнит любой вызов, даже inline
функции). И нужна инструкция синхронизации кешей, чего не явным образом никак не получить.

Все современные вычислительные машины, библиотеки, программы... используют для построения примитивов
синхронизации атомарные инструкции, как правило совмещённые с "аппаратными" барьерами памяти, включающими
в себя не только физическую запись регистров в память компилятором, но и выполнение специальной инструкции,
синхронизирующей кеши у процессоров (без чего, собственно, всё бесполезно! так как другой процессор
иначе эту volatile переменную не увидит).

Ты пользуешься тем, что на x86 архитектуре всё сделано, чтоб подложить соломки индусским программистам,
чтоб оно хоть как-то работало даже если и не должно. ARM или MIPS таких ошибок не простит. Особенно
современный 64-битный ARMv8, ARMv9.

Надо не морочить мозг, если речь про C++, то есть std::atomic. Если голый C -- в GCC есть два набора
builtin функций для того же. Если Windows -- спец. функции в Win32 API.
Re[4]: Volatile и предупреждение C5220
От: σ  
Дата: 03.01.22 14:01
Оценка: 17 (2) +1
М>>>зачем понадобились volatile-переменные?

ЕМ>>Для реализации некоторых легковесных методов синхронизации. Например, там, где циклически выполняется группа операций, и этот цикл нужно останавливать по внешнему сигналу. Использовать там средства ОС избыточно — по уши хватит и volatile-переменных.


fk0> OMG! Полярный песец!


fk0> Volatile не является барьером. Не атомарно. И из него никаких толком алгоритмов не построить, даже

fk0>алгоритм Петерсона требует чтоб число записывалось за один раз, атомарно.

fk0> И самое поганое, запись в volatile-переменные не упорядочена по сравнению с другими обращениями

fk0>к памяти.

В MSVC по-умолчанию доступ к volatile-объектам имеет acquire-release семантику https://docs.microsoft.com/en-us/cpp/cpp/volatile-cpp?view=msvc-170#end-of-iso-conformant
Отредактировано 03.01.2022 14:03 σ . Предыдущая версия .
Re[3]: Volatile и предупреждение C5220
От: fk0 Россия https://fk0.name
Дата: 03.01.22 14:03
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:

М>>зачем понадобились volatile-переменные?


ЕМ>Для реализации некоторых легковесных методов синхронизации. Например, там, где циклически выполняется группа операций, и этот цикл нужно останавливать по внешнему сигналу. Использовать там средства ОС избыточно — по уши хватит и volatile-переменных.


И этот человек что-то тут про говнокод современных программистов рассуждает!
Re[13]: Volatile и предупреждение C5220
От: Максим Россия  
Дата: 03.01.22 14:05
Оценка:
ЕМ>Напомню, вопрос возник потому, что компилятор предупреждает не о недостаточности volatile для синхронизации, а о "нетривиальности" автоматически генерируемого конструктора класса, содержащего volatile-переменную.

Были какие-то разногласия между членами комитета на этот счет. Возможно найдете что-то полезное по ссылке ниже
Copying volatile subobjects is not trivial
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1153r0.html

М>>Можете показать примерный код?

ЕМ>
ЕМ>class C {

ЕМ>  int volatile i;

ЕМ>};
ЕМ>


Тут volatile можно убрать, ничего принципиально не изменится (надо просто проверить, что компилятор не выкинет i на данном уровне оптимизации).

В свете вышесказанного про майкрософтовский компилятор, этод код осуществляет синхронизацию, да.
Errare humanum est
Отредактировано 03.01.2022 14:11 Максим . Предыдущая версия .
Re[12]: Volatile и предупреждение C5220
От: σ  
Дата: 03.01.22 14:06
Оценка:
ЕМ>>Фраза "за это отвечает код" подразумевает, что код использует необходимые механизмы, явно или неявно.
М>Я никак не могу понять, что конкретно вы делаете для этого? Если это volatile, то это не синхронизация от слова совсем.

https://docs.microsoft.com/en-us/cpp/cpp/volatile-cpp?view=msvc-170#end-of-iso-conformant:
> When the /volatile:ms compiler option is used—by default when architectures other than ARM are targeted—the compiler generates extra code to maintain ordering among references to volatile objects in addition to maintaining ordering to references to other global objects.
> …
> This enables volatile objects to be used for memory locks and releases in multithreaded applications.
Re[5]: Volatile и предупреждение C5220
От: Максим Россия  
Дата: 03.01.22 14:07
Оценка:
σ>В MSVC по-умолчанию доступ к volatile-объектам имеет acquire-release семантику https://docs.microsoft.com/en-us/cpp/cpp/volatile-cpp?view=msvc-170#end-of-iso-conformant

Ах вот оно что! Спасибо! А я гадаю, как это код у Евгения вообще работает.

Вот это правда немного смущает

When it relies on the enhanced guarantee that's provided when the /volatile:ms compiler option is used, the code is non-portable.

Errare humanum est
Отредактировано 03.01.2022 14:08 Максим . Предыдущая версия .
Re[5]: Volatile и предупреждение C5220
От: fk0 Россия https://fk0.name
Дата: 03.01.22 14:10
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, Максим, Вы писали:


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


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


Volatile достаточно бессмысленная вещь, т.к. не гарантирует ПОРЯДКА ОПЕРАЦИЙ.
Это основная проблема. В рамках функции компилятор всё может переупорядочить.
Кроме того, для чего выставлены явные барьеры конечно.

Кроме того, даже если в компиляторе ты сделал -O0, или написал руками на ассемблере, и оно
всё получилось в нужном тебе порядке, сам процессор не гарантирует, что другие процессоры
(ядра) увидят данные в том порядке, как они у тебя записаны в память. Потому, что без
каких-то инструкций со стороны программы процессор данные вначале закеширует у себя,
а потом, когда-нибудь, начнёт медленно и печально записывать в общую память/кеш
в неизвестно каком порядке. Кроме систем с write through, но сейчас таких вроде не
остаётся уже (ибо медленно).

М>>Лучше использовать гарантированно lock-free на любых платформах std::atomic_flag

ЕМ>Мне пока не актуальны платформы, отличные от x86/x64, даже ARM под большим вопросом. Ну и не люблю я библиотечных конструкций в ядерном коде — они то реализованы "с особенностями", то тянут за собой лишний код из CRT, то не реализованы вообще.

Чушь какая. Они РЕАЛИЗОВАНЫ и работают -- это ключевое. Как не важно, тем более, что на
современных процессорах именно что через спец. инструкции процессора и инлайнятся прямо
по месту, без вызова каких-то функций, и тем более без походов в ядро (что наблюдалось на
старых армах).
Re[7]: Volatile и предупреждение C5220
От: fk0 Россия https://fk0.name
Дата: 03.01.22 14:12
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:


ЕМ>Эти рассуждения годятся для программирования на C++ в стиле каких-нибудь Python или JS, где программа имеет дело с абстрактной виртуальной средой.


Я вообще не понимаю, как чего-то может добиться человек не обладающий абстрактным мышлением.

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

Я уже вижу типичные макароны фортран-говнокода. Тьфу, тошно.
Re[12]: Volatile и предупреждение C5220
От: fk0 Россия https://fk0.name
Дата: 03.01.22 14:17
Оценка: 6 (1)
Здравствуйте, Максим, Вы писали:

ЕМ>>Фраза "за это отвечает код" подразумевает, что код использует необходимые механизмы, явно или неявно.

М>Я никак не могу понять, что конкретно вы делаете для этого? Если это volatile, то это не синхронизация от слова совсем. Можете показать примерный код?

Ничего он не делает. У него чудом оно работает на х86.

Тут есть объяснялово: https://www.arangodb.com/2021/02/cpp-memory-model-migrating-from-x86-to-arm/

Если вкратце, то у x86 специально сделано "попроще", чтоб индусский код не развалился.
Re[5]: Volatile и предупреждение C5220
От: fk0 Россия https://fk0.name
Дата: 03.01.22 14:23
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

SaZ>>Можно явно указать стандарт в параметрах сборки.

ЕМ>Я б с радостью, но VC++ не умеет ниже C++14.

Ну вот, программисты тоже устаревают безнадёжно...

ЕМ>Мне пока более всего интересно, в чем может заключаться фактическая нетривиальность конструктора и/или оператора присваивания, которые мог бы сгенерить компилятор по новому стандарту. Вы об этом что-нибудь знаете?


Тем, что volatile переменная должна записаться сколько положено раз, а не
быть просто присвоена оконечным результатом расчитанным чуть ли не в compile time.

С учётом ряда оптимизаций выполняемых компилятором для "нормальных" классов и функций
это выполнить сложно. RVO/NRVO (copy elision) оптимизации в частности невозможны.

Ситуация усугубляется тем, что компилятор после C++17 обязан делать copy elision.
Re[5]: Volatile и предупреждение C5220
От: fk0 Россия https://fk0.name
Дата: 03.01.22 14:25
Оценка: :)
Здравствуйте, σ, Вы писали:

fk0>> И самое поганое, запись в volatile-переменные не упорядочена по сравнению с другими обращениями

fk0>>к памяти.

σ>В MSVC по-умолчанию доступ к volatile-объектам имеет acquire-release семантику https://docs.microsoft.com/en-us/cpp/cpp/volatile-cpp?view=msvc-170#end-of-iso-conformant


Вот я и говорю, Intel и Microsoft подстелили соломки, чтоб индусы не больно падали.
Re[13]: Volatile и предупреждение C5220
От: Максим Россия  
Дата: 03.01.22 14:29
Оценка:
fk0> Ничего он не делает. У него чудом оно работает на х86.

Тут дело не только в х86, но и в компиляторе от майкрософт. По ссылке от сигмы видно, что они интерпретируют volatile как условный atomic с Acquire/Release semantics, что приводит к неявной синхронизации

When the /volatile:ms compiler option is used—by default when architectures other than ARM are targeted—the compiler generates extra code to maintain ordering among references to volatile objects in addition to maintaining ordering to references to other global objects

https://docs.microsoft.com/en-us/cpp/cpp/volatile-cpp?view=msvc-170#end-of-iso-conformant

Было бы интересно, если Евгений собрал проект без этой опции. Подозреваю, многое может измениться в поведении программы
Errare humanum est
Re[6]: Volatile и предупреждение C5220
От: Максим Россия  
Дата: 03.01.22 14:31
Оценка:
fk0> Вот я и говорю, Intel и Microsoft подстелили соломки, чтоб индусы не больно падали.

+1. В любом случае так писать опасно. Завтра поменяют настройки компилятора и здравствуй ночи за отладчиком.
Errare humanum est
Re[4]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 03.01.22 15:34
Оценка:
Здравствуйте, fk0, Вы писали:

fk0>Volatile не является барьером. Не атомарно.


Мне это (внезапно) известно.

fk0>на x86 архитектуре всё сделано, чтоб подложить соломки индусским программистам


На x86 это было сделано в конце 80-х, задолго до появления феномена "индусского кода". И сделано в первую очередь для того, чтобы не ломать совместимость с уже существующим двоичным кодом.
Re[4]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 03.01.22 15:35
Оценка:
Здравствуйте, fk0, Вы писали:

fk0>И этот человек что-то тут про говнокод современных программистов рассуждает!


А точнее?
Re[14]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 03.01.22 15:37
Оценка:
Здравствуйте, Максим, Вы писали:

М>В свете вышесказанного про майкрософтовский компилятор, этод код осуществляет синхронизацию, да.


Я дополнительно слежу за тем, чтобы реально осуществлялась запись в память. volatile мне нужно исключительно для контроля чтения.
Re[6]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 03.01.22 15:38
Оценка:
Здравствуйте, Максим, Вы писали:

М>Вот это правда немного смущает

М>

М>When it relies on the enhanced guarantee that's provided when the /volatile:ms compiler option is used, the code is non-portable.


В большинстве случаев переносимый код не требуется. У меня один из таких. Когда будет нужен именно переносимый, я сделаю необходимые изменения.
Re[6]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 03.01.22 16:17
Оценка:
Здравствуйте, fk0, Вы писали:

fk0>процессор не гарантирует, что другие процессоры ядра) увидят данные в том порядке, как они у тебя записаны в память.


Я об этом (внезапно) знаю, и мне этого не требуется.
Re[8]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 03.01.22 16:18
Оценка:
Здравствуйте, fk0, Вы писали:

fk0>Я вообще не понимаю, как чего-то может добиться человек не обладающий абстрактным мышлением.


А я не понимаю, в чем связь между наличием/отсутствием абстрактного мышления и ориентацией на абстрактную вычислительную среду.
Re[6]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 03.01.22 16:32
Оценка:
Здравствуйте, fk0, Вы писали:

ЕМ>>VC++ не умеет ниже C++14.


fk0> Ну вот, программисты тоже устаревают безнадёжно...


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

ЕМ>>в чем может заключаться фактическая нетривиальность конструктора и/или оператора присваивания, которые мог бы сгенерить компилятор по новому стандарту.


fk0>Тем, что volatile переменная должна записаться сколько положено раз


С чего вдруг? И как это связано с тривиальностью/нетривиальностью?
Re[7]: Volatile и предупреждение C5220
От: fk0 Россия https://fk0.name
Дата: 04.01.22 14:21
Оценка: 16 (1) +2
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>>>VC++ не умеет ниже C++14.

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

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

ЕМ>>>в чем может заключаться фактическая нетривиальность конструктора и/или оператора присваивания, которые мог бы сгенерить компилятор по новому стандарту.

fk0>>Тем, что volatile переменная должна записаться сколько положено раз
ЕМ>С чего вдруг?

Из определения volatile и следует.

volatile object — an object whose type is volatile-qualified, or a subobject of a volatile object, or a mutable subobject of a const-volatile object. Every access (read or write operation, member function call, etc.) made through a glvalue expression of volatile-qualified type is treated as a visible side-effect for the purposes of optimization (that is, within a single thread of execution, volatile accesses cannot be optimized out or reordered with another visible side effect that is sequenced-before or sequenced-after the volatile access. This makes volatile objects suitable for communication with a signal handler, but not with another thread of execution, see std::memory_order). Any attempt to refer to a volatile object through a glvalue of non-volatile type (e.g. through a reference or pointer to non-volatile type) results in undefined behavior.



ЕМ> И как это связано с тривиальностью/нетривиальностью?


Так, что невозможно компилятор сделать, чтоб он удовлетворял требованиям по обращению с volatile-переменными.
Их, например, через memcpy() даже копировать нельзя. Потому, что в библиотеке сильно-оптимизированный вариант
функции memcpy() хрен знает как разорвёт блок памяти по словам, что-то скопирует по байтам, что-то по длинным
словам (через FPU, векторные расширения).

Буквально, скопировать объект с volatile-переменной -- нетривиальная задача. Для этого нужно сгенерировать
специальную функцию, которая умеет работать с этим объектом, будет знать там offset для volatile-переменной
и её скопирует аккуратно одной инструкцией.


История проблемы здесь:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1153r0.html

The problem with this is that a volatile qualified type may need to be copied in a specific way (by copying using only atomic operations on multithreaded platforms, for example) in order to avoid the “memory tearing” that may occur with a byte-by-byte copy.

Re[9]: Volatile и предупреждение C5220
От: fk0 Россия https://fk0.name
Дата: 04.01.22 14:31
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

fk0>>Я вообще не понимаю, как чего-то может добиться человек не обладающий абстрактным мышлением.

ЕМ>А я не понимаю, в чем связь между наличием/отсутствием абстрактного мышления и ориентацией на абстрактную вычислительную среду.

Прямая. В очередной раз вижу "я/мы делаем продукт под конкретную вычислительную платформу и ничего не хотим знать..."
(потому, что старенькие) про то как это делается в более общем случае, для абстрактной вычислительной среды,
в рамках которой стандарт C++ и существует. И если это знание использовать -- то работает сразу и на любой архитектуре.

А если говорить, что я старенький, ничего не хочу знать, в 2003 году и так работало (на процессоре выпущенном в тех
же годах), вообще ваш C++ он ууух плохой, там жырный код и страшные темплейты... Java тоже плохая и ООП изобрели идиоты,
какая-либо методология разработки ПО тоже не нужна ибо Java и bloatware, шаблоны проектирования -- тоже жырный ентерпрайз
нам не нужно. Вот мы молодцы сейчас на ассемблере напишем свой memcpy() который 8.9 раз медленее версии написанной на C.

ТОШНО, АЖ СИЛ НЕТ.
Re[5]: Volatile и предупреждение C5220
От: _NN_ www.nemerleweb.com
Дата: 04.01.22 14:53
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Мне пока не актуальны платформы, отличные от x86/x64, даже ARM под большим вопросом. Ну и не люблю я библиотечных конструкций в ядерном коде — они то реализованы "с особенностями", то тянут за собой лишний код из CRT, то не реализованы вообще.


Это не так сложно и затратно как кажется.
Мы используем в ядре весь набор type_traits, atomic и ещё по мелочи.
Работает стабильно.

Из действительно неприятного это отсутствие тривиального конструктора у std::atomic в C++20, обходится явной инициализацией в {}
https://github.com/microsoft/STL/issues/661
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Volatile и предупреждение C5220
От: fk0 Россия https://fk0.name
Дата: 04.01.22 15:18
Оценка: 10 (1)
Здравствуйте, Евгений Музыченко, Вы писали:

volatile можно использовать только как, условно, volatile bool флаг, как аналог типа данных sig_atomic_t.
Чтоб один поток (обработчик прерывания, сигнала) мог сообщить другому о возникновении какого-либо атомарного
(событие либо произошло, либо нет) события. И в этом случае необходимость использования volatile скорей
вытекает из того, что где-то есть цикл и без volatile компилятор просто не будет перечитывать переменную,
так как имеет уверенность, что текущий поток её никак не может модифицировать.

И существует другая возможность, вставить просто компиляторный барьер, что заставит компилятор перечитать
память и выключит "оптимизацию" цикла. В чистом виде сам volatile вообще ни за чем не нужен, кроме случаев
когда переменная -- регистр специального назначения изменяемый аппаратурой. А использование volatile не
по делу только создаёт трудности компилятору по оптимизации кода.

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

Вот всё что нужно знать. И такое использование volatile актуально было более 10 лет назад, до появления C++11.
И то, больше от дурости, т.к. решается барьером или вызовом любой функции, что срабатывает как барьер.
В любом случае, когда это возможно проще, надёжней, использовать std::atomic (с соответствующим memory order,
если нужна оптимизация).
Re: Volatile и предупреждение C5220
От: Alexander G Украина  
Дата: 04.01.22 17:31
Оценка: 12 (1)
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>От этого можно как-то избавиться, кроме как принудительно запретить эти предупреждения?


Я бы сказал, это баг. Зарепортил https://developercommunity.visualstudio.com/t/Superfluous-warning-C5220/162849

Заткнуть можно локально:
struct S{

    volatile int v;
#pragma warning  (suppress:5220)
};


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


ЕМ>Вообще, что за "нетривиальность" оно имеет в виду?


См. std::is_trivially_copyable. Грубо говоря, поэлементное копирование, которое может быть выполнено во время компиляции и полностью вы-оптимизировано.

Т.е. они говорят, что раньше могли выбросить конструктор компирования, а теперь больше не будут.

Сравните https://godbolt.org/z/59oWE6vx6
Русский военный корабль идёт ко дну!
Re[8]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 04.01.22 17:34
Оценка:
Здравствуйте, fk0, Вы писали:

fk0>Речь о том, что человек не хочет ничего нового учить, ничего нового не принимает и не понимает, и не хочет понимать.


Люди, которые не хотят изучать ничего нового, являются, как правило, клиентами психиатров. А нежелание изучать новое, несущее больше геморроя, чем пользы, просто потому, что оно ново — вполне разумная тактика управления личными ресурсами. Далеко не все востребованные продукты изготовлены с применением новейших технологий.

fk0>Потому, что он старенький, у него закостенел мозг, и он привык делать как привык.


Если это лично в мой огород, то мимо кассы. Не следует столь обобщать частные случаи.

ЕМ>>И как это связано с тривиальностью/нетривиальностью?


fk0>Так, что невозможно компилятор сделать, чтоб он удовлетворял требованиям по обращению с volatile-переменными.


Не вижу ровно никаких причин для невозможности.

fk0>Их, например, через memcpy() даже копировать нельзя. Потому, что в библиотеке сильно-оптимизированный вариант

fk0>функции memcpy()

При чем здесь библиотека и функция memcpy? Под тривиальностью всегда понималась возможность сгенерировать код, который не обращается к методам класса, не использует виртуальности и т.п. То есть, тривиальность определяется по отсутствию вовлечения языковых средств, находящихся выше генератора кода. В частности, тривиальными являются конструкторы POD. POD с квалификатором volatile тоже всегда относился к тривиальным. Потому я и удивился, увидев, что VC++ 19.x вдруг стал считать их нетривиальными.

fk0>хрен знает как разорвёт блок памяти по словам, что-то скопирует по байтам, что-то по длинным словам (через FPU, векторные расширения).


Всем этим традиционно занимается генератор кода. При таком подходе нужно заодно объявить нетривиальными и float/double, поскольку у многих процессоров вообще нет никакой аппаратной плавучки, и все операции преобразуются в неявные вызовы функций, а в многопроцессорных системах с общим процессорам плавучки нужны еще и приседания с синхронизацией доступа и запретом прерываний.

fk0>Буквально, скопировать объект с volatile-переменной -- нетривиальная задача. Для этого нужно сгенерировать специальную функцию, которая умеет работать с этим объектом, будет знать там offset для volatile-переменной и её скопирует аккуратно одной инструкцией.


Во-первых, это типовая задача кодогенератора, с нею успешно справлялись во все времена. Во-вторых, откуда взялось требование "аккуратно одной инструкцией"? volatile-переменные никогда не заявлялись атомарными, для них гарантировалось всего лишь неприменение отдельных оптимизаций.

fk0>

The problem with this is that a volatile qualified type may need to be copied in a specific way (by copying using only atomic operations on multithreaded platforms, for example) in order to avoid the “memory tearing” that may occur with a byte-by-byte copy.


Вы таки определитесь — то ли volatile "не атомарно", "не является барьером" и якобы вообще не имеет смысла, и тогда для него не нужны никакие дополнительные техники (а лишь отказ от того, что охотно используется для остального), или же это вполне себе рабочий инструмент.
Re[6]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 04.01.22 17:44
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Мы используем в ядре весь набор type_traits, atomic и ещё по мелочи.

_NN>Работает стабильно.

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

std::atomic, конечно, ничего за собой не потянет, но в MSVC++ есть встроенные и предсказуемые _Interlocked*, ими и пользуюсь.
Re[2]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 04.01.22 17:58
Оценка:
Здравствуйте, fk0, Вы писали:

fk0>volatile можно использовать только как, условно, volatile bool флаг, как аналог типа данных sig_atomic_t.

fk0>Чтоб один поток (обработчик прерывания, сигнала) мог сообщить другому о возникновении какого-либо атомарного
fk0>(событие либо произошло, либо нет) события.

Если бы Вы удосужились спросить, для чего именно я использую volatile без atomic-прикрытия, то внезапно обнаружилось бы, что именно для этого. Там, где используются счетчики, test-and-set и подобное, использую соответствующие средства.

Так что, вместо пальца, из которого Вы вдохновенно насосали аж на цельный трактат, имеет смысл рассматривать более достоверные источники.

fk0>В чистом виде сам volatile вообще ни за чем не нужен, кроме случаев когда переменная -- регистр специального назначения изменяемый аппаратурой.


Все встроенные функции _Interlocked* в MSVC++, выполняющие аппаратно атомарные операции, определены с volatile для параметров-указателей. Другое дело, что компилятор не считает ошибкой передачу такой функции переменной без volatile.

fk0>А использование volatile не по делу только создаёт трудности компилятору по оптимизации кода.


Я Вас умоляю. На фоне трудностей, которые ему создают всякие локальные функции, это мышкины слезки.
Re[7]: Volatile и предупреждение C5220
От: _NN_ www.nemerleweb.com
Дата: 04.01.22 18:04
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, _NN_, Вы писали:


_NN>>Мы используем в ядре весь набор type_traits, atomic и ещё по мелочи.

_NN>>Работает стабильно.

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

Что поделать. Такова судьба C++
Если вам повезло использовать C++20, то с концептами код получается гораздо проще в чтении, поддержке и в сообщениях компилятора.
Да ещё и код собирается быстрее.

А вот контейнеры конечно в ядре проблемно.
Хотя есть std::array, и сегодня даже constexpr std::vector.

ЕМ>std::atomic, конечно, ничего за собой не потянет, но в MSVC++ есть встроенные и предсказуемые _Interlocked*, ими и пользуюсь.

С другой стороны используя std::atomic можно не только писать код, который будет работать везде, а ещё и переиспользовать его в других платформах.
Но это, как я понимаю, вам принципиально не актуально.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 04.01.22 18:24
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Заткнуть можно локально:

AG>Но это как мне кажется глупее, чем выключить глобально.

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

ЕМ>>что за "нетривиальность" оно имеет в виду?


AG>См. std::is_trivially_copyable.


Понятно, спасибо. Первый толковый ответ в теме.
Re[8]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 04.01.22 18:29
Оценка: :)
Здравствуйте, _NN_, Вы писали:

_NN>Что поделать. Такова судьба C++


Вот я и пытаюсь, пока возможно, оставаться в рамках C++, который еще не слишком испоганили.

_NN>Если вам повезло использовать C++20, то с концептами код получается гораздо проще в чтении, поддержке и в сообщениях компилятора.

_NN>Да ещё и код собирается быстрее.

Хм, за счет чего быстрее?

_NN>С другой стороны используя std::atomic можно не только писать код, который будет работать везде, а ещё и переиспользовать его в других платформах.

_NN>Но это, как я понимаю, вам принципиально не актуально.

Пока совершенно не актуально. Но не все это понимают. То, что фару с определенной модели мерседеса нельзя поставить никуда, кроме этой же модели мерседеса, почему-то никого не удивляет...
Re[4]: Volatile и предупреждение C5220
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 05.01.22 00:47
Оценка:
Здравствуйте, reversecode, Вы писали:

R>что за чушь ?

Такое вполне работает если можно гарантировать валидность данных. Например, у тебя один поток крутится что-то делая, а из другого потока хочется остановить первый. Делая это через волатайл переменную, надо только гарантировать, что первый поток будет всегда крутится и обрабатывать валидные и некоррапченные данные и выводить корректный результат, ну и первый поток не должен убиваться . Возможно, на каких-то простых операциях это будет работать, но в реальности, да под нагрузкой, этот механизм чаще всего даст сбой, а в сложных системах человек просто забудет про этот небольшой нюанс, что-то удалит ну и всё посыпется. Короче, решение в такое себе.
Sic luceat lux!
Re[7]: Volatile и предупреждение C5220
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 05.01.22 00:49
Оценка: +1 :)
Здравствуйте, Максим, Вы писали:

М>+1. В любом случае так писать опасно. Завтра поменяют настройки компилятора и здравствуй ночи за отладчиком.

Ты не поверишь, но с того что компилятор поменялся и началась эта ветка
Sic luceat lux!
Re[5]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.01.22 10:38
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Возможно, на каких-то простых операциях это будет работать, но в реальности, да под нагрузкой, этот механизм чаще всего даст сбой


У меня это работает под любыми нагрузками. Какие нужны условия, чтоб перестало работать?
Re[14]: Volatile и предупреждение C5220
От: Alexander G Украина  
Дата: 06.01.22 09:08
Оценка:
Здравствуйте, Максим, Вы писали:

М>Было бы интересно, если Евгений собрал проект без этой опции. Подозреваю, многое может измениться в поведении программы


Я подозреваю, что нет.

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

http://rsdn.org/forum/cpp.applied/8167392.1
Автор: Alexander G
Дата: 06.01.22
Русский военный корабль идёт ко дну!
Re[9]: Volatile и предупреждение C5220
От: fk0 Россия https://fk0.name
Дата: 06.01.22 17:55
Оценка: 26 (2)
Здравствуйте, Евгений Музыченко, Вы писали:


ЕМ>Люди, которые не хотят изучать ничего нового, являются, как правило, клиентами психиатров. А нежелание изучать новое, несущее больше геморроя, чем пользы, просто потому, что оно ново — вполне разумная тактика управления личными ресурсами. Далеко не все востребованные продукты изготовлены с применением новейших технологий.


Речь не об использовании новейших технологий, а о том, что нужно понимать, что они возникают
не на пустом месте просто чтоб "быть новыми", а потому, что существует реальная насущная потребность
в них. Сколько-то там лет назад многоядерность была экзотикой, а сейчас в настольном компьютере
20 ядер. И появились средства определённые подходы к програмированию таких систем, о которых
хотя бы поверхностно нужно знать.

ЕМ>>>И как это связано с тривиальностью/нетривиальностью?

fk0>>Так, что невозможно компилятор сделать, чтоб он удовлетворял требованиям по обращению с volatile-переменными.
ЕМ>Не вижу ровно никаких причин для невозможности.

Я ж только что написал, что (N)RVO требуемые стандартом не выполнимы для классов с volatile переменными,
так как два раздела стандарта вступают в противоречие.

fk0>>Их, например, через memcpy() даже копировать нельзя. Потому, что в библиотеке сильно-оптимизированный вариант

fk0>>функции memcpy()

ЕМ>При чем здесь библиотека и функция memcpy? Под тривиальностью всегда понималась возможность сгенерировать код, который не обращается к методам класса, не использует виртуальности и т.п. То есть, тривиальность определяется по отсутствию вовлечения языковых средств, находящихся выше генератора кода. В частности, тривиальными являются конструкторы POD. POD с квалификатором volatile тоже всегда относился к тривиальным. Потому я и удивился, увидев, что VC++ 19.x вдруг стал считать их нетривиальными.


Мотивировка в том, это же очевидно, что для каждого класса с volatile членом нужна генерация уникального
конструктора копирования, уникального конструктора перемещения. Уникального для данного класса. Для обычного
класса, без volatile-переменных, с POD-членами, попросту вызывается memcpy, который даже тут же инлайнится
в месте использования. А в случае с классом у которого внутри volatile -- нужен вызов конкретной функции,
специфичной для данного класса. Что это как не тривиальный конструктор?

fk0>>хрен знает как разорвёт блок памяти по словам, что-то скопирует по байтам, что-то по длинным словам (через FPU, векторные расширения).

ЕМ>Всем этим традиционно занимается генератор кода. При таком подходе нужно заодно объявить нетривиальными и float/double, поскольку у многих процессоров вообще нет никакой аппаратной плавучки, и все операции преобразуются в неявные вызовы функций, а в многопроцессорных системах с общим процессорам плавучки нужны еще и приседания с синхронизацией доступа и запретом прерываний.

Переменные с плавающей точкой на любой архитектуре совершенно обыкновенным образом лежат в памяти
и никаких специальных мер по обращению с ними не требуется. То, что там операционная система при переключении
контекстов вынимает из стека математического сопроцессора числа и сохраняется где-то в структуре контекста
потока -- совершенно не имеет никакого отношения к компилятору. Компилятор класс с float переменными
может скопировать с помощью обычной memcpy. А сопроцессор использует как будто он использует его монопольно
и существует только один поток.

fk0>>Буквально, скопировать объект с volatile-переменной -- нетривиальная задача. Для этого нужно сгенерировать специальную функцию, которая умеет работать с этим объектом, будет знать там offset для volatile-переменной и её скопирует аккуратно одной инструкцией.

ЕМ>Во-первых, это типовая задача кодогенератора, с нею успешно справлялись во все времена.

Не типовая, так как требуется конструктор копирования специфичный для данной функции. Тривиальный
конструктор копирования -- это тот, который не сгенерирован для конкретного класса.

TriviallyCopyable objects can be copied by copying their object representations manually, e.g. with std::memmove. All data types compatible with the C language (POD types) are trivially copyable.


Так вот очевидно, что класс с volatile-переменными невозможно скопировать с помощью memmove.
Это следует из определения volatile-переменной:

Any attempt to refer to a volatile object through a glvalue of non-volatile type (e.g. through a reference or pointer to non-volatile type) results in undefined behavior.


ЕМ> Во-вторых, откуда взялось требование "аккуратно одной инструкцией"? volatile-переменные никогда не заявлялись атомарными, для них гарантировалось всего лишь неприменение отдельных оптимизаций.


Volatile переменная тем не менее не может считываться компилятором по два раза вместо одного (что произойдёт при побайтовом
копировании, например). Типичный пример -- SFR-регистры, которые изменяют состояние периферии при считывании. Да у них ширина
в машинное слово и их нужно читать одной инструкцией. И нельзя читать два раза если у компилятора не хватает регистров и он
соптимизировал вникуда локальную переменную в которой хранится копия.

По факту чтение volatile запросто атомарно до тех пор, пока такая переменная выровненная и имеет соответствующий размер.

fk0>>

The problem with this is that a volatile qualified type may need to be copied in a specific way (by copying using only atomic operations on multithreaded platforms, for example) in order to avoid the “memory tearing” that may occur with a byte-by-byte copy.


ЕМ>Вы таки определитесь — то ли volatile "не атомарно", "не является барьером" и якобы вообще не имеет смысла, и тогда для него не нужны никакие дополнительные техники (а лишь отказ от того, что охотно используется для остального), или же это вполне себе рабочий инструмент.


Изменение volatile-переменной -- не атомарно. RISC-процессоры вообще не имеют инструкций (кроме SWAP на ARM) для
чтения-модификации-записи в одной инструкции, например... Чтение или запись де-факто в определенных обстоятельствах --
атомарно и этим часто пользуются.

Смысла процитированной фразы я не смог понять. Volatile имеет смысл для того, для чего предназначен -- для работы
с SFR-регистрами преимущественно (чтение или запись которых изменяет состояние аппаратуры). Volatile позволяет
гарантировать, что обращение к переменной произойдёт ровно так как написано в коде. Ровно один раз, например,
а не два или три подряд (потому, что компилятор сгенерировал такой код, потому, что регистровому аллокатору не
хватило регистров).

Volatile не предназначен для синхронизации потоков и ничего для этого не предоставляет. И уж тем более не предназначен
для синхронизации процессоров с общим полем памяти.

Для синхронизации потоков нужно заставить компилятор физически произвести запись в память в нужное время, в нужном
месте. Volatile этого не гарантирует (повторю, что компилятор может запросто "оптимизировать" логику так, что все
volatile переменные заипишет либо раньше времени, либо позже, относительно записи не-volatile ячеек памяти, относительно
других инструкций процессора, включая запрет прерываний, и т.п.) Для упорядочивания обращений к памяти со стороны
компилятора существует понятие компиляторного барьера памяти, чем является выражение вида asm("nop" ::: "memory) в GCC,
или даже просто вызов любой функции (кроме случая static-функции...) Компилятор должен записать всё в память перед барьером,
и чтения-записи которыев программе после барьера они будут сделаны точно после.

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

Volatile всего этого -- не даёт. Использование volatile скорей имеет корни в том, что есть такой частый паттерн,
когда запускается поток, в котором в цикле выполняется какая-то работа, и цикл прерывается по переменной-флагу.
И компилятор для обычной, не-volatile переменной попросту оптимизирует цикл в бесконечный. Так как видит, что
переменная не может никак быть изменена. По идее, если переменная-флаг может использоваться хоть в какой-то другой функции,
то такой оптимизации происходить не может. Однако если весь код состоит из static-переменных или функций и компилятор
построив граф вызовов понимает, что переменная изменена быть не может -- вправе выполнить такую оптимизацию.
И способ избежать такой оптимизации -- использовать volatile. Либо использовав memory barrier, либо отметить только
одну проблемную переменную, как в примере по ссылке: https://godbolt.org/z/37hfeY76M

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

Volatile просто не средство для синхронизации потоков и процессоров, вот и всё что следует знать.
Для синхронизации потоков есть барьеры, для синхронизации процессоров -- специальные инструкции процессора.
И в целом это всё вручную делать обычно нет необходимости, так как существуют, предоставляемые C/C++ библиотекой
более высокоуровневые примитивы синхронизации, такие как мьютексы (являющиеся барьерами с нужной acquire/release
семантикой) и атомарные переменные. Которые просто "работают из коробки". И их следует в нормальном случае
использовать. А код с volatile -- это нечто странно выглядящее и таящее в себе неведомые сюрпризы.
Re[3]: Volatile и предупреждение C5220
От: fk0 Россия https://fk0.name
Дата: 06.01.22 18:19
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

fk0>>В чистом виде сам volatile вообще ни за чем не нужен, кроме случаев когда переменная -- регистр специального назначения изменяемый аппаратурой.

ЕМ>Все встроенные функции _Interlocked* в MSVC++, выполняющие аппаратно атомарные операции, определены с volatile для параметров-указателей. Другое дело, что компилятор не считает ошибкой передачу такой функции переменной без volatile.

volatile в прототипе функции достаточно бессмысленная вещь.

fk0>>А использование volatile не по делу только создаёт трудности компилятору по оптимизации кода.

ЕМ>Я Вас умоляю. На фоне трудностей, которые ему создают всякие локальные функции, это мышкины слезки.

Вот эти слезки: https://godbolt.org/z/Wdo7hP4bj https://godbolt.org/z/E6M7xTPax

У микрософта volatile ломает оптимизацию (скорей потому, что микрософт строго соответствует букве стандарта)
и заставляет генерировать как раз специфичный для класса конструктор копирования, здесь он заинлайнен в цикл,
но сам факт, что memcpy -- не работает. Для сколько-нибудь сложного класса вместо memcpy будет уже вызов
функции конструктора копирования в цикле. И не работает RVO.
Re[2]: Volatile и предупреждение C5220
От: Андрей Тарасевич Беларусь  
Дата: 06.01.22 19:05
Оценка:
Здравствуйте, Alexander G, Вы писали:
AG>Сравните https://godbolt.org/z/59oWE6vx6

И что же именно мы там должны увидеть? В окне справа я вижу value-initialization. Но вот "конструктор копирования" там странслировался в какой-то бессмысленный набор ничего не делающих инструкций.
Best regards,
Андрей Тарасевич
Re[3]: Volatile и предупреждение C5220
От: Alexander G Украина  
Дата: 06.01.22 20:31
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ> Но вот "конструктор копирования" там странслировался в какой-то бессмысленный набор ничего не делающих инструкций.


Ха, действительно. Не всмотрелся, ожидал именно копирования. Тогда согласен, не знаю, что там мы должны увидеть.
Русский военный корабль идёт ко дну!
Re[8]: Volatile и предупреждение C5220
От: ksandro Мухосранск  
Дата: 07.01.22 23:21
Оценка:
Здравствуйте, Максим, Вы писали:

М>Ну так да. Самый простой сценарий. Есть пременная flag которая в одном потоке читается, что-то в духе

М>
М>while(flag) {...}
М>

М>а во втором изменяется
М>
М>flag = false
М>


М>Так вот, изменяя переменную во втором потоке, мы не знаем когда эти изменения "прилетят" в первый поток. Все зависит от того, где находится эта самая переменная, когда будут сброшены процессорные кеши итд.


Я кстати, видел именно такой код с остановкой цикла по выставлению флага. Эта конструкция использовалась для корректного завершения программы (останавливаем все потоки, освобождаем все ресурсы). И оно много лет прекрасно работало (возможно и сейчас работает), компилировалось это дело сначала разными версиями gcc потом clang, но только под x86. Проблем никогда не возникало. Мне тогда очень хотелось заменить это на atomic, но мне сказали "работает не трогай!".

Я так понимаю, на x86 такой код не должен вызывать проблем. Да, изменяя переменную во втором потоке мы не знаем точно, когда изменения прилетят в первый поток, но они гарантированно прилетят, и это будет за небольшое время. Если у нас просто один флаг который нужен для остановки цикла, нам совсем не важен точный порядок записи чтения. Но вообще было бы интересно узнать, возможны ли какие-то реальные проблемы именно с этим кодом на x86? И какие реальные проблемы могут быть на других платформах (я никогда не работал с ARM, но правильно ли я понимаю, что там изменение переменной может так и не прилететь в читающий поток)?
Re[9]: Volatile и предупреждение C5220
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 08.01.22 13:12
Оценка: 1 (1)
Здравствуйте, ksandro, Вы писали:

K>И оно много лет прекрасно работало (возможно и сейчас работает)


Не "возможно", а точно работает. И будет работать до тех пор, пока обеспечивается двоичная совместимость.

K>(я никогда не работал с ARM, но правильно ли я понимаю, что там изменение переменной может так и не прилететь в читающий поток)?


Никогда не прилетит оно только в одном случае — когда ядро, на котором работает записавший поток, никогда не изменит режима выполнения (прерывание, исключение, вызов привилегированного кода и т.п.). А такое возможно либо при глухом зависании ядра (при котором нормальная работа остальных ядер будет под вопросом), либо при работе софта на голом железе (без ОС).

В случае типовой работы под ОС, типовой же сценарий — установить флаг и перейти к ожиданию, вызвав примитив ОС типа Wait, Sleep, Delay и т.п. Эти примитивы выполняются через исключение или специальные операции вызова привилегированного кода. Даже если при этом процессор аппаратно не сбросит буферы — это сделает обработчик ОС.
Re[9]: Volatile и предупреждение C5220
От: vsb Казахстан  
Дата: 10.01.22 13:44
Оценка: +1
Здравствуйте, ksandro, Вы писали:

K>Я кстати, видел именно такой код с остановкой цикла по выставлению флага. Эта конструкция использовалась для корректного завершения программы (останавливаем все потоки, освобождаем все ресурсы). И оно много лет прекрасно работало (возможно и сейчас работает), компилировалось это дело сначала разными версиями gcc потом clang, но только под x86. Проблем никогда не возникало. Мне тогда очень хотелось заменить это на atomic, но мне сказали "работает не трогай!".


K>Я так понимаю, на x86 такой код не должен вызывать проблем. Да, изменяя переменную во втором потоке мы не знаем точно, когда изменения прилетят в первый поток, но они гарантированно прилетят, и это будет за небольшое время. Если у нас просто один флаг который нужен для остановки цикла, нам совсем не важен точный порядок записи чтения. Но вообще было бы интересно узнать, возможны ли какие-то реальные проблемы именно с этим кодом на x86? И какие реальные проблемы могут быть на других платформах (я никогда не работал с ARM, но правильно ли я понимаю, что там изменение переменной может так и не прилететь в читающий поток)?


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