Здравствуйте, fk0, Вы писали:
ЕМ>>VC++ не умеет ниже C++14.
fk0> Ну вот, программисты тоже устаревают безнадёжно...
Использование свежих стандартов языка не является показателем качества программного продукта.
ЕМ>>в чем может заключаться фактическая нетривиальность конструктора и/или оператора присваивания, которые мог бы сгенерить компилятор по новому стандарту.
fk0>Тем, что volatile переменная должна записаться сколько положено раз
С чего вдруг? И как это связано с тривиальностью/нетривиальностью?
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>>>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-переменной
и её скопирует аккуратно одной инструкцией.
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.
Здравствуйте, Евгений Музыченко, Вы писали:
fk0>>Я вообще не понимаю, как чего-то может добиться человек не обладающий абстрактным мышлением. ЕМ>А я не понимаю, в чем связь между наличием/отсутствием абстрактного мышления и ориентацией на абстрактную вычислительную среду.
Прямая. В очередной раз вижу "я/мы делаем продукт под конкретную вычислительную платформу и ничего не хотим знать..."
(потому, что старенькие) про то как это делается в более общем случае, для абстрактной вычислительной среды,
в рамках которой стандарт C++ и существует. И если это знание использовать -- то работает сразу и на любой архитектуре.
А если говорить, что я старенький, ничего не хочу знать, в 2003 году и так работало (на процессоре выпущенном в тех
же годах), вообще ваш C++ он ууух плохой, там жырный код и страшные темплейты... Java тоже плохая и ООП изобрели идиоты,
какая-либо методология разработки ПО тоже не нужна ибо Java и bloatware, шаблоны проектирования -- тоже жырный ентерпрайз
нам не нужно. Вот мы молодцы сейчас на ассемблере напишем свой memcpy() который 8.9 раз медленее версии написанной на C.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Мне пока не актуальны платформы, отличные от x86/x64, даже ARM под большим вопросом. Ну и не люблю я библиотечных конструкций в ядерном коде — они то реализованы "с особенностями", то тянут за собой лишний код из CRT, то не реализованы вообще.
Это не так сложно и затратно как кажется.
Мы используем в ядре весь набор type_traits, atomic и ещё по мелочи.
Работает стабильно.
Из действительно неприятного это отсутствие тривиального конструктора у std::atomic в C++20, обходится явной инициализацией в {} https://github.com/microsoft/STL/issues/661
volatile можно использовать только как, условно, volatile bool флаг, как аналог типа данных sig_atomic_t.
Чтоб один поток (обработчик прерывания, сигнала) мог сообщить другому о возникновении какого-либо атомарного
(событие либо произошло, либо нет) события. И в этом случае необходимость использования volatile скорей
вытекает из того, что где-то есть цикл и без volatile компилятор просто не будет перечитывать переменную,
так как имеет уверенность, что текущий поток её никак не может модифицировать.
И существует другая возможность, вставить просто компиляторный барьер, что заставит компилятор перечитать
память и выключит "оптимизацию" цикла. В чистом виде сам volatile вообще ни за чем не нужен, кроме случаев
когда переменная -- регистр специального назначения изменяемый аппаратурой. А использование volatile не
по делу только создаёт трудности компилятору по оптимизации кода.
И больше ни для чего разумно volatile использовать нельзя. И нельзя даже использовать комбинацию такого
флага с какими-либо другими переменными, так как порядок записи (на уровне кеша процессора, а не инструкций)
не определён.
Вот всё что нужно знать. И такое использование volatile актуально было более 10 лет назад, до появления C++11.
И то, больше от дурости, т.к. решается барьером или вызовом любой функции, что срабатывает как барьер.
В любом случае, когда это возможно проще, надёжней, использовать std::atomic (с соответствующим memory order,
если нужна оптимизация).
struct S{
volatile int v;
#pragma warning (suppress:5220)
};
Но это как мне кажется глупее, чем выключить глобально.
Если от воринига нет пользы, и он выключен по умолчанию, почему бы его не выключить.
ЕМ>Вообще, что за "нетривиальность" оно имеет в виду?
См. std::is_trivially_copyable. Грубо говоря, поэлементное копирование, которое может быть выполнено во время компиляции и полностью вы-оптимизировано.
Т.е. они говорят, что раньше могли выбросить конструктор компирования, а теперь больше не будут.
Здравствуйте, 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 "не атомарно", "не является барьером" и якобы вообще не имеет смысла, и тогда для него не нужны никакие дополнительные техники (а лишь отказ от того, что охотно используется для остального), или же это вполне себе рабочий инструмент.
Здравствуйте, _NN_, Вы писали:
_NN>Мы используем в ядре весь набор type_traits, atomic и ещё по мелочи. _NN>Работает стабильно.
Ну, type traits, насколько я понимаю, полностью реализован на шаблонах, полностью раскрываемых во время компиляции, и не порождающих кода. Этих фич я не люблю в основном за то, что построены на извращенных идеях, и при малейшей ошибке вылезает такая диагностика, что проще сразу выкинуть, чем разбираться, где и почему ошибка. А библиотечные средства, порождающие код, стараюсь не использовать там, где критично время выполнения. Несколько раз пытался использовать контейнеры, но они сразу тянут за собой поддержку из CRT, которая или конфликтует с моей моделью (некоторые проекты вообще не используют CRT), или вообще не работает в ядре.
std::atomic, конечно, ничего за собой не потянет, но в MSVC++ есть встроенные и предсказуемые _Interlocked*, ими и пользуюсь.
Здравствуйте, fk0, Вы писали:
fk0>volatile можно использовать только как, условно, volatile bool флаг, как аналог типа данных sig_atomic_t. fk0>Чтоб один поток (обработчик прерывания, сигнала) мог сообщить другому о возникновении какого-либо атомарного fk0>(событие либо произошло, либо нет) события.
Если бы Вы удосужились спросить, для чего именно я использую volatile без atomic-прикрытия, то внезапно обнаружилось бы, что именно для этого. Там, где используются счетчики, test-and-set и подобное, использую соответствующие средства.
Так что, вместо пальца, из которого Вы вдохновенно насосали аж на цельный трактат, имеет смысл рассматривать более достоверные источники.
fk0>В чистом виде сам volatile вообще ни за чем не нужен, кроме случаев когда переменная -- регистр специального назначения изменяемый аппаратурой.
Все встроенные функции _Interlocked* в MSVC++, выполняющие аппаратно атомарные операции, определены с volatile для параметров-указателей. Другое дело, что компилятор не считает ошибкой передачу такой функции переменной без volatile.
fk0>А использование volatile не по делу только создаёт трудности компилятору по оптимизации кода.
Я Вас умоляю. На фоне трудностей, которые ему создают всякие локальные функции, это мышкины слезки.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, _NN_, Вы писали:
_NN>>Мы используем в ядре весь набор type_traits, atomic и ещё по мелочи. _NN>>Работает стабильно.
ЕМ>Ну, type traits, насколько я понимаю, полностью реализован на шаблонах, полностью раскрываемых во время компиляции, и не порождающих кода. Этих фич я не люблю в основном за то, что построены на извращенных идеях, и при малейшей ошибке вылезает такая диагностика, что проще сразу выкинуть, чем разбираться, где и почему ошибка. А библиотечные средства, порождающие код, стараюсь не использовать там, где критично время выполнения. Несколько раз пытался использовать контейнеры, но они сразу тянут за собой поддержку из CRT, которая или конфликтует с моей моделью (некоторые проекты вообще не используют CRT), или вообще не работает в ядре.
Что поделать. Такова судьба C++
Если вам повезло использовать C++20, то с концептами код получается гораздо проще в чтении, поддержке и в сообщениях компилятора.
Да ещё и код собирается быстрее.
А вот контейнеры конечно в ядре проблемно.
Хотя есть std::array, и сегодня даже constexpr std::vector.
ЕМ>std::atomic, конечно, ничего за собой не потянет, но в MSVC++ есть встроенные и предсказуемые _Interlocked*, ими и пользуюсь.
С другой стороны используя std::atomic можно не только писать код, который будет работать везде, а ещё и переиспользовать его в других платформах.
Но это, как я понимаю, вам принципиально не актуально.
Здравствуйте, Alexander G, Вы писали:
AG>Заткнуть можно локально: AG>Но это как мне кажется глупее, чем выключить глобально.
Понятно, что можно отключить глобально, но я думал, что это предупреждение может быть полезным в каких-нибудь других ситуациях.
ЕМ>>что за "нетривиальность" оно имеет в виду?
AG>См. std::is_trivially_copyable.
Здравствуйте, _NN_, Вы писали:
_NN>Что поделать. Такова судьба C++
Вот я и пытаюсь, пока возможно, оставаться в рамках C++, который еще не слишком испоганили.
_NN>Если вам повезло использовать C++20, то с концептами код получается гораздо проще в чтении, поддержке и в сообщениях компилятора. _NN>Да ещё и код собирается быстрее.
Хм, за счет чего быстрее?
_NN>С другой стороны используя std::atomic можно не только писать код, который будет работать везде, а ещё и переиспользовать его в других платформах. _NN>Но это, как я понимаю, вам принципиально не актуально.
Пока совершенно не актуально. Но не все это понимают. То, что фару с определенной модели мерседеса нельзя поставить никуда, кроме этой же модели мерседеса, почему-то никого не удивляет...
Здравствуйте, reversecode, Вы писали:
R>что за чушь ?
Такое вполне работает если можно гарантировать валидность данных. Например, у тебя один поток крутится что-то делая, а из другого потока хочется остановить первый. Делая это через волатайл переменную, надо только гарантировать, что первый поток будет всегда крутится и обрабатывать валидные и некоррапченные данные и выводить корректный результат, ну и первый поток не должен убиваться . Возможно, на каких-то простых операциях это будет работать, но в реальности, да под нагрузкой, этот механизм чаще всего даст сбой, а в сложных системах человек просто забудет про этот небольшой нюанс, что-то удалит ну и всё посыпется. Короче, решение в такое себе.
Здравствуйте, Максим, Вы писали:
М>+1. В любом случае так писать опасно. Завтра поменяют настройки компилятора и здравствуй ночи за отладчиком.
Ты не поверишь, но с того что компилятор поменялся и началась эта ветка
Здравствуйте, Kernan, Вы писали:
K>Возможно, на каких-то простых операциях это будет работать, но в реальности, да под нагрузкой, этот механизм чаще всего даст сбой
У меня это работает под любыми нагрузками. Какие нужны условия, чтоб перестало работать?
Здравствуйте, Максим, Вы писали:
М>Было бы интересно, если Евгений собрал проект без этой опции. Подозреваю, многое может измениться в поведении программы
Я подозреваю, что нет.
Также думаю, что вопрос заслуживает вынесения из темы "как заткнуть этот ворнинг" и обсуждения без срача.