Re[44]: Безопасность Rust
От: vdimas Россия  
Дата: 04.06.19 08:00
Оценка:
Здравствуйте, Sinclair, Вы писали:

V>>Факт разработки языка Си для целей написания UNIX подтверждённый.

S>Всегда восторгаюсь способности нести чушь с умным видом.

Это из-за недостатка понимания у тебя.


S>Ничего, что слово volatile появилось в С через 15 лет после того, как переписывание ядра UNIX на него закончилось?


Например как здесь путаешь появление в стандарте с появлением в компиляторе.
Бывает. ))
volatile появился одновременно с первыми попытками снабдить Си-компиляторы оптимизацией.


S>Ну, и мелочи вроде путания Linux и UNIX, то есть дедушки с внуком, они как бы тоже прекрасны в рамках данной дискуссии с претензией на понимание не только фактов, но и причинно-следственных связей.


Что показывает тебя вовсей красе, бо я давно поправился и без сопливых:
http://www.rsdn.org/forum/flame.comp/7460557.1
Re[36]: Безопасность Rust
От: vdimas Россия  
Дата: 04.06.19 08:23
Оценка:
Здравствуйте, alex_public, Вы писали:

_>И подробное обсуждение всей этой кривизны можно увидеть здесь https://github.com/michaeljclark/riscv-atomics/tree/master/results.


0000000000000020 <atomic_store_explicit_int32_t_memory_order_relaxed>:
  20:    00000797              auipc    a5,0x0
  24:    00078793              mv    a5,a5
  28:    4705                    li    a4,1
  2a:    c398                    sw    a4,0(a5)


А как быть с контролем выравнивания?
Моя версия объяснения:
http://www.rsdn.org/forum/flame.comp/7460823.1

(а так-то обилие багов в деле генерировании флагов команд ужасает, походу этот RISC-V никому не нужен, если gcc генерит для него явно ошибочный код)
Отредактировано 04.06.2019 11:00 vdimas . Предыдущая версия .
Re[45]: Безопасность Rust
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.06.19 09:10
Оценка: +2 :)
Здравствуйте, vdimas, Вы писали:

V>Это из-за недостатка понимания у тебя.



V>Например как здесь путаешь появление в стандарте с появлением в компиляторе.

Не, не путаю.
V>volatile появился одновременно с первыми попытками снабдить Си-компиляторы оптимизацией.
И вы, конечно же, сможете указать, что это были за компиляторы, и в каком году они вышли, да? Ну, чтобы мы убедились, что без ключевого слова volatile разработка многозадачной операционной системы UNIX была немыслима, так ведь?
V>Что показывает тебя вовсей красе, бо я давно поправился и без сопливых:
V>http://www.rsdn.org/forum/flame.comp/7460557.1
Ну, это же так — вишенка на торте.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[46]: Безопасность Rust
От: vdimas Россия  
Дата: 04.06.19 10:12
Оценка:
Здравствуйте, Sinclair, Вы писали:

V>>volatile появился одновременно с первыми попытками снабдить Си-компиляторы оптимизацией.

S>И вы, конечно же, сможете указать, что это были за компиляторы, и в каком году они вышли, да?

Ну ты же начал с дат появления volatile, но назвал (случайно ли?) дату появления этого ключевого слова в стандарте.
При том, что я пользовался этим ключевым словом в Borland Turbo C 2.0, а тот вышел раньше публикации стандарта.
Т.е. ты ошибся в своих громогласных утверждениях про 15 лет. ))


S>Ну, чтобы мы убедились, что без ключевого слова volatile разработка многозадачной операционной системы UNIX была немыслима, так ведь?


Пока что я убеждаюсь в твоём полнейшем непонимании:

volatile появился одновременно с первыми попытками снабдить Си-компиляторы оптимизацией.

Без оптимизаций volatile НЕ нужен.

И да, разработка систем UNIX-семейства в те года никогда не заканчивалась, если что.

В общем, тут всё просто — найди дату появления первых оптимизирующих компиляторов Си и ты автоматом найдёшь дату появления volatile.


V>>Что показывает тебя вовсей красе, бо я давно поправился и без сопливых:

V>>http://www.rsdn.org/forum/flame.comp/7460557.1
S>Ну, это же так — вишенка на торте.

Осталось определиться, к чьему портрету, бгг.
Re[36]: Безопасность Rust
От: · Великобритания  
Дата: 04.06.19 10:13
Оценка: :)
Здравствуйте, alex_public, Вы писали:

_>>>Ох, ну что за детский сад. Ты реально не в курсе что такое mfence? Ну мне даже лень объяснять, так что поясню проще: https://godbolt.org/z/7zWFvr — с точки зрения вопросов атомарности это в точности тот же самых код с вполне корректным std::atomic, что и раньше, только переписанный чуть под другому. Дальше сам додумаешь? )))

_>·>А как это объяснишь? https://godbolt.org/z/LLNDkD
_>Это кривая реализация встроенной функции gcc __atomic_store_n для данной маргинальной платформы. Собственно тут (https://github.com/michaeljclark/riscv-atomics) можно увидеть две реализации и та, что на сайте godbolt, использует именно кривой вариант через встроенную функцию gcc, а не через ассемблер. Нормальную реализацию можно увидеть например здесь https://github.com/michaeljclark/riscv-atomics/blob/master/src/stdatomic_asm.h#L95. И подробное обсуждение всей этой кривизны можно увидеть здесь https://github.com/michaeljclark/riscv-atomics/tree/master/results.
Ок, ты в очередной раз подменяешь тезис. Но пусть кривая. В любом случае, она ничему не противоречит и имеет право на жизнь. Возможно лишь ухудшает перформанс.
И уж тем более это никак не доказывает, что volatile sig_atomic можно использовать в многопоточке. Доказательством будет фраза в стандарте. А стандарт наоборот это явно запрещает.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[45]: Безопасность Rust
От: · Великобритания  
Дата: 04.06.19 10:56
Оценка:
Здравствуйте, vdimas, Вы писали:

V>·>"многопоточность в языке" означает, что язык описывает поведение языковых конструкций в контексте многих потоков.

V>·>volatile же описывает поведение языка в контексте асинхронных сигналов.
V>Я уже отвечал на это — где появился volatile, там многопоточность работала поверх одного процессора.
И что? volatile не определяет поведение в условиях многопоточности. А если поведение не определено, то это называется undefined behaviour.

V>>>такого пояснения было недостаточно?

V>·>То что можно дёрнуть syscall для создания потоков это ещё не значит, что язык умеет потоки.
V>Ес-но.
V>Поэтому я и не утверждал, что "в языке есть потоки", я утверждал, что в языке есть "понятие о многопоточности".
Но только начиная с 11.

V>>>Факт разработки языка Си для целей написания UNIX подтверждённый.

V>·>Интересует взаимосвязь этого факта с многопоточностью.
V>UNIX многозадачна by design.
И что? Ты путаешь операционку и язык программирования. Мы обсуждаем многопоточность в контексте языка программирования.

V>>>Я бы даже усилил — в отсутствии эрудиции и присутствии необоснованного упрямства — натуральная проблема.

V>·>"А в стандарте C11 в язык добавили реализацию потоков и поддержку атомарных типов"
V>До С++11 жизни не было, что ле?
В языке — не было. Конструкции языка вели себя "как карта ляжет" в условиях многопоточности. Надо было соответствующим образом взаимодействовать с конкретной платформой конкретным образом для написания корректного кода.

V>>>Если тебя интересует другая модель многопоточности, то просьба уточнить, какая именно.

V>·>Перечисли модели многопоточности какие есть в языке С/С++.
V>В языке Си нет никаких моделей многопоточности.
V>Модель многопоточности — это абстракция, от языка зависит мало.
Именно. Так что конкретно ты меня просишь уточнить?

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

Верно, но это никак магически не расширяется на многопоточность.

V>В стандарт С++11 добавили поддержку конкретно SMP-многопоточности.

V>Заметь, не в конструкции языка, а в стандартизированную часть его библиотек.
Именно в конструкции.

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

Если "вычисления и побочные эффекты выражений" это часть библиотек, то я — Папа Римский.

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

И ты можешь это подтвердить ссылкой на стандарт?

V>>>Как работает Linux, которая писана и вовсе на голом С?

V>·>Linux не написана целиком на С, а вот такие критические платформенно-зависимые вещи типа атомарности, тредов и прочего частенько пишется на соответствующем ассемблере.
V>Это верно для той эпохи, когда появились interlocked-операции, но компиляторы их еще не поддерживали.
V>Я и сам выдирал из исходников линухов ассемблерные вставки в 2000-х для реализации cas в отстутствии соотвeтствующих built-in's в gcc.
Как же так? Язык умел в многопоточность, а gcc не умел? Плохой gcc!

V>>>Собсно, я всё это уже перечислял тут многократно, тебе стоило спорить с моими утверждениями целиком.

V>·>Возможно будет, но этого нет в стандарте языка, а значит UB.
V>Тут работает более одного пункта стандарта одновременно.
V>К уже процитированному добавляется:
V>

V>6.8.2.1.20
V>Two actions are potentially concurrent if
V>(20.1) — they are performed by different threads, or
V>(20.2) — they are unsequenced, at least one is performed by a signal handler, and they are not both performed
V>by the same signal handler invocation.
V>...
V>The execution of a program contains a data race if it contains two potentially concurrent conflicting actions,
V>at least one of which is not atomic...
V>Any such data race results in undefined behavior.

Верно. И теперь тебе осталось разобраться что в данном месте называется "atomic".
Хинт: это не sig_atomic и не volatile. В твоей цитате стандарта ниже это есть.

V>>>По стандарту UB будет только при доступе к нескольким переменным.

V>·>Хватит бла-бла. Приведи ссылку на стандарт.
V>Тебе приводились цитаты из cppreference.
V>Ссылка на то же самое на английском:
V>https://en.cppreference.com/w/cpp/atomic/memory_order
V>

V>when multiple threads simultaneously read and write to several variables, one thread can observe the values change in an order different from the order another thread wrote them.

С этим согласен. Но ты написал слово "только" — это неверно.

V>Собсно, до прошлого сообщения я и сам не понимал, что тебе может быть непонятного в самоописываемом идентификаторе memory_order?

Мне непонятно, почему ты игнорируешь всё остальное относящееся к memory model.

V>A program that has two conflicting evaluations has a data race unless:
V>- both evaluations execute on the same thread or in the same signal handler, or
V>- both conflicting evaluations are atomic operations (see std::atomic), or
V>- one of the conflicting evaluations happens-before another (see std::memory_order)

V>Ключевое выделил.
V>Теперь вернись на прошлое моё сообщение и медитируй до просветления.
Да, выделил третий пункт, но проигнорировал второй, написав "только".

V>>>Я показал тебе алгоритм, который абсолютно корректен с т.з. стандартов.

V>·>Ты показал сигналы, а не многопоточность. И да, тот код корректен, но к многопоточности отношения не имеет.
V>Мякотка в том, что тебе никто не запрещает вызывать тот хенлдер сигнала ручками из другого потока.
Прямой вызов хендлера ясен пень будет некорректным (ведь это будет тупо вызов функции с т.з. языка), но ты можешь послать сигнал самому себе — а это уже совсем другая опера.

V>Дабы исключить лишний пинг-понг, на этот счёт тоже есть оговорки в стандарте:

V>

V>6.8.2.1.23
V>Transformations that introduce a speculative read of a potentially shared memory location may not
V>preserve the semantics of the C++ program as defined in this document, since they potentially introduce a
V>data race. However, they are typically valid in the context of an optimizing compiler that targets a specific
V>machine with well-defined semantics for data races.

А самое важное ты, конечно, обрезал:

They would be invalid for a hypothetical machine that is not tolerant of races or provides hardware race detection.

но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[46]: Безопасность Rust
От: vdimas Россия  
Дата: 04.06.19 11:12
Оценка:
Здравствуйте, ·, Вы писали:

·>volatile не определяет поведение в условиях многопоточности.


Ес-но, но с этим никто и не спорил.


·>А если поведение не определено, то это называется undefined behaviour.


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


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

·>Но только начиная с 11.

Пфф...

С высоты птичьего полёта, вся эта ветка спора — очередное классическое "С++ говно".
При том, что с высоты птичьего полёта, действительно, для многих ниш С++ говно, но в невообразимом кол-ве частностей — это самый проработанный на сегодня язык, в сравнении с другими мейнстримовыми (я сходу могу назвать кучу недоработок, например, в языке C# 7.3, на котором плотно сейчас сижу).

В этом смысле, пытающиеся доказать, что "С++ говно" через частности совершают тактическую ошибку.
Бо это проще делать на макроуровне, эдакими широкими жестами сравнивая целые ниши/отрасли и/или на хорошо обкатанном негролинчинге, навроде существования голых указателей и отсутствия проверок при выходе за границу встроенных в язык массивов.

Всё остальное грозит бумерангом вернуться к линчевателям, испортить им настроение и непременно перевести обсуждение в русло спора ради спора, т.е. к напрасному потреблению терпения друг друга.
Re[37]: Безопасность Rust
От: vdimas Россия  
Дата: 04.06.19 11:36
Оценка:
Здравствуйте, ·, Вы писали:

·>И уж тем более это никак не доказывает, что volatile sig_atomic можно использовать в многопоточке. Доказательством будет фраза в стандарте. А стандарт наоборот это явно запрещает.


Стандарт не так говорит.
В разделе о гонках он говорит, например, о действиях A и B, и говорит, что volatile не даёт механизма из другого потока восстановить последовательность действий.
Везде оперируется словом order.
Про "запрещает" там ничего нет.
Тебе никто ничего не запрещает.
Например, некоторые межпоточные алгоритмы подразумевают наличие явных гонок, для их работы достаточно атомарности, но совершенно не требуется восстановления порядка действий.
Re[44]: Безопасность Rust
От: · Великобритания  
Дата: 04.06.19 11:50
Оценка:
Здравствуйте, vdimas, Вы писали:

V>·>После очередной подмены тезис стал заключаться в том, что atomic<int>+relaxed и volatile sig_atomic_t — оба атомарны с т.з. многопоточности т.к. генерят одинаковый код. Я показал, что иногда генерится разный код. ЧТД.

V>Не-не-не, Дэвид Блэйн, вы показывали Алексу, что в одном случае атомарность, а в другом нет.
Нет, Алекс пытался доказать что sig_atomic_t атомарен с т.з. многопоточности на том основании, что генерится одинаковый код. Это у него заняло несколько попыток. Последний результат — он назвал текущую имплементацию в gcc бажной. Но это всё мягко говоря не в тему, т.к. это всё равно не докажет многопоточную атомарность, ибо даже если посмотреть на доку по atomic_signal_fence, то ассемблерный код ничего не подтверждает, ибо "This is equivalent to std::atomic_thread_fence, except no CPU instructions for memory ordering are issued".

V>Тем самым ты и Сайберикс показали, что не понимаете, что есть атомарность, путаете её с упорядочиванием/синхронизацией.

Это ты путаешь. Нет такого понятия "нет упорядоченности", а есть order_relaxed.

V>А я лишь утверждал о требовании записи значения в память в одну инструкцию из-за работы в условиях прерываний.

Это я как раз и упомянул первым. Ты же совершенно необоснованно пытаешься это натянуть на многопоточность. Хотя стандарт явно разделяет эти понятия. Посмотри хотя бы на наличие atomic_signal_fence и atomic_thread_fence.

V>·>В любом случае, даже если risc и все известные архитектуры будут атомик по самые гланды, это не меняет того факта, что по стандарту _языка_ ни int, ни даже volatile int не являются atomic.

V>По стандарту sig_atomic_t в любом случае будет atomic.
Не в контексте многопоточки, т.к. такое его использование — data race, а значит ub. Использование std::atomic не является data race.

V>Симметричная мякотка в том, что в многопроцессорной системе обработчик прерывания может быть вызыван из другого потока (из основного), а не из того, в котором ты осуществляешь оперироавние с переменной типа sig_atomic_t.

Верно. Но это обработчик сигнала будет вызван снаружи. А тред должен дёргать signal(). В этом случае сработают соответсвующие механизмы atomic.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[47]: Безопасность Rust
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.06.19 12:12
Оценка: 2 (1) +1 :)
Здравствуйте, vdimas, Вы писали:

V>При том, что я пользовался этим ключевым словом в Borland Turbo C 2.0, а тот вышел раньше публикации стандарта.

Ну, всё правильно. Вышел он в конце 1988 (в штатах). А в марте 1988 вышло второе издание K&R с описанием этого слова.
Это вы, коллега, путаете дату официального утверждения стандарта с датами публикации. Так-то комитет начал работать ещё в 1982, и делал это вовсе не в тишине.
До примерно 1983-84 никакого "множества компиляторов" в природе не существовало — был компилятор Джонсона и его порты на разные платформы.

V>Т.е. ты ошибся в своих громогласных утверждениях про 15 лет. ))

не-не-не. Мои утверждения никакие не громогласные. Я тихонечко напоминаю мастерам художественного вымысла, что C активно использовался для переписывания ядра UNIX в 1967-1972 годах, как раз за 15 лет до выхода Turbo C 1.0 с его оптимизациями.
Так что volatile вошёл в обращение примерно в 1985, и в "разработке Unix" не фигурировал.

S>>Ну, чтобы мы убедились, что без ключевого слова volatile разработка многозадачной операционной системы UNIX была немыслима, так ведь?


V>Пока что я убеждаюсь в твоём полнейшем непонимании:

V>

V>volatile появился одновременно с первыми попытками снабдить Си-компиляторы оптимизацией.

V>Без оптимизаций volatile НЕ нужен.

V>И да, разработка систем UNIX-семейства в те года никогда не заканчивалась, если что.

Разработка Unix на С началась ещё в 60х. К концу 70х, когда появилась The Big Blue C, переписывание ядра на С практически закончилось.
А Джонсон занялся разработкой портируемого компилятора С, который был основой усилий по портированию Unix на всё подряд — это как раз с 1977 по 1984.
И вот только после этого начались подвижки в сторону оптимизаций и volatile; до этого пользователей компилятора больше волновала портируемость, а не оптимизации.

Сопоставление этих фактов и даёт нам понимание того, что "volatile является понятием многопоточности в языке C, придуманным для нужд системы Unix" является всего лишь забавным заблуждением.
По факту, в те времена, когда язык пилился "для целей операционки", никаким volatile в нём и не пахло. И только внезапный его выход далеко за пределы этой ниши и дал толчок к появлению volatile.

Cовременный взгляд на применение volatile "для целей операционки" вам изложить, или вы его и так знаете?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[33]: Безопасность Rust
От: alex_public  
Дата: 04.06.19 12:36
Оценка:
Здравствуйте, ·, Вы писали:

_>>·>Ты видимо что-то не понимаешь, что значит "гарантии". То что в современных платформах это обычно так, это не значит, что это чем-то гарантированно. Я завтра могу спаять новую платформу где это будет не так и твой говнокод поломается и тебе придётся править баги.

_>>Я правильно понимаю это как признание, что на самом деле таких заявленных платформ ты не знаешь? )
·>Нет, не знаю. И что? Из моего незнания будешь делать выводы?

Да не уж то что-то подобное адекватному общению. Только вот как долго мы к этому шли...

_>>·>Кстати, такое было в 8088 — инструкции 16-битные, а шина 8-битная. Т.е. запись регистра 16 бит полезет в ячейки памяти дважды. Правда многопоточноть никто на этих чипах не реализовывал.

_>>Абсолютно нормально там работала бы многопоточность (в рамках одного ядра), т.к, инструкция то одна была. А вот реализовывать многоядерным такого уродца точно никто бы не стал. )))
·>А ты клянёшься, что никто никода не станет?

Эм, в наше время все эти разборки между ядрами разрешаются исключительно на уровне кэша, т.е. до самой памяти конкурирующие инструкции вообще никогда не добираются. Разрешение конфликтов происходит аккурат между первым уровнем общего кэша и уровнем последнего локального кэша ядра, по соответствующему протоколу поддержки когерентности. Причём минимальным атомарным куском перекидываемых данных там является даже не регистр, а линия кэша (например для Intel это сейчас 64 байта). Так вот самое интересное заключается в том, что это всё сейчас передаётся по последовательной шине данных (у того же Intel'a она называется кажется QuickPath)! Так что да, я уверен, что разрядность шины в современных реалиях не будет проблемой. )))

_>>Точка передачи (планировщик) там в любом случае будет unsafe, просто потому, что его по другому не сделать. И мы будем ему доверять на слово, так же как другим подобным инструментам (типа Mutex, Atomic и т.п.). Вопрос в коде внутри самих сопрограмм: он получается может быть валидным или нет в зависимости от некой программной опции — сомневаюсь что такое возможно разумно задать с помощью системы типов. )

·>Эээ? А что там такого невозможного? По большому счёту это просто синт-сахар. На гарантии корректности тут мало что влияет.

Ладно, это бестолковый разговор сейчас — посмотрим как они реализуют их в стандарте языка и как оно будет дружить с многопоточностью (в C++ это просто отдано на откуп программисту). Ну т.е. в Rust'е и сейчас можно попробовать поиграться в stackful сопрограммки типа этой https://github.com/rustcc/coroutine-rs обёртки вокруг Boost.Context, но как видишь и в них это всё только в мечтах о будущем... )))

_>>·>Атомарность вообще-то подразумевает ещё и видимость значений. Если в коде значение переменной присваивается, то вполне ожидаемо, что значение таки изменится. Отсутствие барьеров может нарушить эту гарантию.

_>>Так последнее значение в любом случае присвоится, даже если компилятор выкинет промежуточные присвоения — всё в рамках ожидания.
·>Но не факт, например, что компилятор не выкинет чтение из памяти.

Ты похоже невнимательно читал мои сообщения или же не понял просто. Вот прямо для того, чтобы не выкинул, и используется ключевое слово volatile. Оно как раз гарантирует отсутствие всех оптимизаций на обращение к такой переменной, кроме переупорядочивания. См. пример тут https://godbolt.org/z/Q1SUha.

А выкидывание при переупорядочивание возможно у других данных, вокруг разделяемой переменной. Т.е. речь шла исключительно о такой https://godbolt.org/z/PMl-pN оптимизации, которую обычный int (или даже volatile) допускает, а atomic нет, потому как по умолчанию у него включена опция дополнительной гарантии последовательности выполнения.

_>>Volatile — это не про сигналы и не про потоки. Это на самом деле очень простая вещь: указание компилятору на то, что к данной переменной может иметь доступ какой-то посторонний код (который компилятору не виден). Это резко сужает набор оптимизаций (в том числе уход в регистр), которые можно применять к этой переменной. Всё, точка. Атомарность, многопоточность, сигналы, упорядоченность записи/чтения и т.п. — это всё уже другие темы, не относящиеся к volatile.

·>В смысле ты считаешь, что в цитате не говорится про сигналы и потоки? Или что? Каким образом твои слова согласуются с цитатой? Или ты цитату считаешь неверной?

Как работает volatile я тебе показал выше. У тебя ещё какие-то вопросы по этому поводу остались или больше нет?

_>>>>·>Это какой процессор не умеет? cli/sti — умеют как минимум все. А если мы говорим о многопроцессорных системах...

_>>>>Эээ что? Ну ты прямо развеселил... Весь даже если бы тебе дали доступ к управлению прерываниями ради такой ерунды как инкремент int'a, это всё равно действовало бы только в рамках одного ядра, а другим ядрам было бы всё равно.
_>>·>Управлением прерываниями занимается ось, притом конкретный механизм управления зависит от конкретного железа. И она же даёт мне доступ к этой магии через сисколы.
_>>Не очень понял эту твою фразу. Ты тут хотел сказать, что на каком-то железе команда запрета прерываний подействует сразу на все ядра или что? )))
·>Ты спросил выше "Какими ещё lock инструкциями, если наш процессор их не умеет" — и внезапно "все ядра". Бывают многоядерные системы, без инструкций синхронизации?

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

_>>>>Аааа, т.е. это ты просто очередной раз написал свой бред не в тему (сам же перед этим писал "Там про race condition."), а просто потому что надо написать что-то, но по теме сказать нечего? ) Ну понятно, понятно... )))

_>>·>Я просто повторил свой тезис, в ответ на твой бред.
_>>Давай ка я кратко перескажу весь наш диалог, а ты попробуешь взглянуть на него со стороны и оценить, можно ли твоё общение считать хотя немного адекватным. И так:
·>А давай я кратко перескажу диалог как я вижу:

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

·>Давай так. по каждому пункту. Ответь — "согласен/не согласен". Если "не согласен", то приводи ссылку на спеку.

·>1. Safe rust даёт гарантии от data race.

Прежде чем согласиться или нет, надо в начале определить что такое "Safe rust". А то я что-то не помню официального определения. Единственное чётко формулируемое (причём даже на уровне компилятора), это "код в котором нет вызовов unsafe кода". Но как ты знаешь, при таком определение safe rust тебе банально даже не удастся завести в нём многопоточность (потому как те же Mutex и т.п. внутри unsafe). Т.е. я подозреваю, что подразумевается какое-то иное определение — озвучь его.

·>2. Доступ через volatile не является atomic.


Модификатор volatile вообще никак не связан с атомарностью. Т.е. через него могут быть определены как атомарные объекты, так и нет.

·>3. Конкурентный доступ из разных потоков к volatile является data race.


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

·>4. data race является undefined behavriour.


Само собой. Причём в наихудшем понимание. Т.е. если говорить например о C++, то во многих местах языка, отмеченных как UB, на самом деле происходят вполне однозначные вещи, просто стандарт говорит о том, что это всё за пределами его понимания. Но есть и места, где UB означает что реально творится "какая-то произвольная ерунда" и data race конечно же относится именно к таким плохим случаям.
Re[38]: Безопасность Rust
От: · Великобритания  
Дата: 04.06.19 13:19
Оценка:
Здравствуйте, vdimas, Вы писали:

V>·>И уж тем более это никак не доказывает, что volatile sig_atomic можно использовать в многопоточке. Доказательством будет фраза в стандарте. А стандарт наоборот это явно запрещает.

V>Стандарт не так говорит.
Вот же:

A program that has two conflicting evaluations has a data race unless

* both evaluations execute on the same thread or in the same signal handler, or
* both conflicting evaluations are atomic operations (see std::atomic), or
* one of the conflicting evaluations happens-before another (see std::memory_order)

If a data race occurs, the behavior of the program is undefined.

Ни sig_atomic, ни volatile не подходят ни под один из указанных пунктов. Следовательно это data race. А значит поведение неопределено.
Оно не то что "запрещает", и таки да, использвать можно, но это будет undefined behaviour. Если тебе хочется писать код, который ведёт себя непредсказуемым образом, то кто ж тебе запретит...
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[45]: Безопасность Rust
От: vdimas Россия  
Дата: 04.06.19 13:19
Оценка:
Здравствуйте, ·, Вы писали:

V>>Не-не-не, Дэвид Блэйн, вы показывали Алексу, что в одном случае атомарность, а в другом нет.

·>Нет, Алекс пытался доказать что sig_atomic_t атомарен с т.з. многопоточности на том основании, что генерится одинаковый код. Это у него заняло несколько попыток. Последний результат — он назвал текущую имплементацию в gcc бажной.

Назвал другой человек, всерьёз проверивший этот момент, Алекс привёл ссылки.

Примечательно было то, что в реализации, про которую говорится, что она верная, действительно, генерируется простое sw в случае memory_order_release.


·>Но это всё мягко говоря не в тему, т.к. это всё равно не докажет многопоточную атомарность


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


V>>Тем самым ты и Сайберикс показали, что не понимаете, что есть атомарность, путаете её с упорядочиванием/синхронизацией.

·>Это ты путаешь. Нет такого понятия "нет упорядоченности", а есть order_relaxed.

))
Речь о гарантиях сохранения упорядоченности и возможности её нарушения.

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


V>>А я лишь утверждал о требовании записи значения в память в одну инструкцию из-за работы в условиях прерываний.

·>Это я как раз и упомянул первым. Ты же совершенно необоснованно пытаешься это натянуть на многопоточность.

Свои обоснования я приводил — из-за механизма вытеснения через прерывание.
Отвечать надо на конкретные доводы, а не эдаким широким жестом — "необоснованно!".


·>Хотя стандарт явно разделяет эти понятия. Посмотри хотя бы на наличие atomic_signal_fence и atomic_thread_fence.


Дык, первое запрещает переупорядочивание инструкций компилятором в этой точке, второй запрещает переупорядочивание инструкций внутри процессора.

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

Есть еще и третий барьер, не введённый пока в стандарт С++ — это полная синхронизация когерентных кешей всех ядер.
(не уверен, что такое будет когда-нить в стандарте, но в современных ОС такая ф-ия есть)



V>>По стандарту sig_atomic_t в любом случае будет atomic.

·>Не в контексте многопоточки

Де-факто в контексте.


·>т.к. такое его использование — data race, а значит ub. Использование std::atomic не является data race.


1. Data race не всегда UB, часто так и задумано.

2. Использование std::atomic, защищает от data race неатомарные типы, для специализаций под эти типы структура std::atomic содержит внутри себя мьютекс.
Что характерно, что для таких типов memory_order не играет никакого значения, т.к. оперирование примитивами синхронизации означает выполнение самых строгих гарантий, т.е. обсуждаемый memory_order актуален только для типов, которые проц умеет сохранять/читать атомарно.


V>>Симметричная мякотка в том, что в многопроцессорной системе обработчик прерывания может быть вызыван из другого потока (из основного), а не из того, в котором ты осуществляешь оперироавние с переменной типа sig_atomic_t.

·>Верно. Но это обработчик сигнала будет вызван снаружи.

Не важно.


·>А тред должен дёргать signal().


Вызов signal устанавливает обработчика, а не генерирует сигнал.
Сигнал посылает kill/raise/alarm.
Сигнал посылается процессу, а не потоку.
Для посылки сигнала потоку есть отдельная ф-ия в либе pthread.


·>В этом случае сработают соответсвующие механизмы atomic.


А как до атомик-то жили? ))

Notes
Until C++11, which introduced std::atomic and std::atomic_signal_fence, about the only thing a strictly conforming program could do in a signal handler was to assign a value to a volatile static std::sig_atomic_t variable and promptly return.


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

Т.е. обработчики сигнала могут работать конкурентно, т.е. конкурентно писать в переменную volatile static std::sig_atomic_t variable из двух одновременно работающих физических потоков на многопроцессорной/многоядерной технике.
И всё должно при этом работать непротиворечиво.
Т.е., как ни крути, но писать конкурентно в sig_atomic_t не возбраняется.
Re[34]: Безопасность Rust
От: · Великобритания  
Дата: 04.06.19 13:43
Оценка:
Здравствуйте, alex_public, Вы писали:


_>·>Давай так. по каждому пункту. Ответь — "согласен/не согласен". Если "не согласен", то приводи ссылку на спеку.

_>·>1. Safe rust даёт гарантии от data race.
_>Прежде чем согласиться или нет, надо в начале определить что такое "Safe rust". А то я что-то не помню официального определения. Единственное чётко формулируемое (причём даже на уровне компилятора), это "код в котором нет вызовов unsafe кода". Но как ты знаешь, при таком определение safe rust тебе банально даже не удастся завести в нём многопоточность (потому как те же Mutex и т.п. внутри unsafe). Т.е. я подозреваю, что подразумевается какое-то иное определение — озвучь его.
Код, который использует safe-конструкции. Примечание: наличие ключевого слова "unsafe" автоматически не означает что данная конструкция перестаёт быть safe, т.к. safety может быть доказана отдельно (вручную человеком, например).

_>·>2. Доступ через volatile не является atomic.

_>Модификатор volatile вообще никак не связан с атомарностью. Т.е. через него могут быть определены как атомарные объекты, так и нет.
Ок. Сформулирую поточнее. "volatile sig_atomic_t" — не является atomic с т.з. многопоточности.

_>·>3. Конкурентный доступ из разных потоков к volatile является data race.

_>Для начала надо определить что такое "доступ" (какие операции конкретно)
Как минимум одна операция записи и ещё одна операция чтения-или-записи.

_>и к каким конкретно типам (volatile же это модификатор, а не тип).

"volatile sig_atomic_t"

_>Для определённых операций (типа записи/чтения) и определённых типов данных (помещающихся в регистр целевой архитектуры) гонок не будет. А для других случаев будут.

Ссылку на стандарт в студию.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[48]: Безопасность Rust
От: vdimas Россия  
Дата: 04.06.19 13:52
Оценка: -1
Здравствуйте, Sinclair, Вы писали:

V>>При том, что я пользовался этим ключевым словом в Borland Turbo C 2.0, а тот вышел раньше публикации стандарта.

S>Ну, всё правильно. Вышел он в конце 1988 (в штатах). А в марте 1988 вышло второе издание K&R с описанием этого слова.

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

Поэтому, твои попытки привязать появление этого ключевого слова к дате стандарта — это ж залёт, курсант! ))


S>Это вы, коллега, путаете дату официального утверждения стандарта с датами публикации.


Забегал...
Там в годы разница, а не в месяцы.


S>Так-то комитет начал работать ещё в 1982, и делал это вовсе не в тишине.


Если хочешь сослаться на некий драфты по годам — не томи, ссылайся.


S>До примерно 1983-84 никакого "множества компиляторов" в природе не существовало — был компилятор Джонсона и его порты на разные платформы.


Это утверждение не позволяет подтверждать или опровергать мысль о том, что компилятор с 67-го года не развивался.


V>>Т.е. ты ошибся в своих громогласных утверждениях про 15 лет. ))

S>не-не-не. Мои утверждения никакие не громогласные. Я тихонечко напоминаю мастерам художественного вымысла, что C активно использовался для переписывания ядра UNIX в 1967-1972 годах

До 74-го года шла работа над той реализацией UNIX.
И после этого еще больше активизировалась.


S>как раз за 15 лет до выхода Turbo C 1.0 с его оптимизациями.


Turbo C — это интегрированная среда разработки плюс компилятор. Компилятор был взят со стороны, некий Wizard C, который на тот момент уже существовал некоторое время.

В общем, ты этот глобус на сову уже не натянешь. ))


S>Так что volatile вошёл в обращение примерно в 1985, и в "разработке Unix" не фигурировал.


При том, что как раз в конце 70-х и все 80-е вовсю разрабатывались операционки семейства UNIX?
Почитай уже историю развития BSD, что ле.


V>>И да, разработка систем UNIX-семейства в те года никогда не заканчивалась, если что.

S>Разработка Unix на С началась ещё в 60х.

И что? ))
Это никак не отменяет твоей попытки приписать оппоненту некую удобную тебе мысль.


S>А Джонсон занялся разработкой портируемого компилятора С, который был основой усилий по портированию Unix на всё подряд — это как раз с 1977 по 1984.

S>И вот только после этого начались подвижки в сторону оптимизаций и volatile; до этого пользователей компилятора больше волновала портируемость, а не оптимизации.
S>Сопоставление этих фактов и даёт нам понимание того, что "volatile является понятием многопоточности в языке C, придуманным для нужд системы Unix" является всего лишь забавным заблуждением.

Сам себе противоречишь.
Сначала соглашаешься с тем, что необходимость volatile для UNIX возникла, хоть и не сразу, но в другом предложении ты утверждаешь, что не возникла, оказывается.
Забавная беготня.


S>По факту, в те времена, когда язык пилился "для целей операционки", никаким volatile в нём и не пахло.


По-факту, язык и продолжил пилиться для целей операционки.
И до сих пор пилится.
Аттрибуты в Си появились тоже для целей операционки изначально, а теперь уже в стандарте.


S>И только внезапный его выход далеко за пределы этой ниши и дал толчок к появлению volatile.


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


S>Cовременный взгляд на применение volatile "для целей операционки" вам изложить, или вы его и так знаете?


Давай я тебя подстрахую от надобности затем натягивать очередных сов на глобусы или наоборот: современный взгляд можно почерпнуть из исходников Linux, например.
Re[39]: Безопасность Rust
От: vdimas Россия  
Дата: 04.06.19 13:56
Оценка:
Здравствуйте, ·, Вы писали:

V>>·>И уж тем более это никак не доказывает, что volatile sig_atomic можно использовать в многопоточке. Доказательством будет фраза в стандарте. А стандарт наоборот это явно запрещает.

V>>Стандарт не так говорит.
·>Вот же:

Раздел стандарта 6.8.2 очень большой, там много чего говорится.
Чтобы не копировать сюда десятки экранов цитирования стандарта, я тебе дал в сухом остатке.

Включив честность и осилив этот раздел целиком, включая notes об аппаратном обеспечении атомарности для некоторых типов на некоторых платформах, ты бы давно перешёл к осмысленному обсуждению. ))
Re[37]: Безопасность Rust
От: alex_public  
Дата: 04.06.19 14:10
Оценка: +1
Здравствуйте, ·, Вы писали:

_>>·>А как это объяснишь? https://godbolt.org/z/LLNDkD

_>>Это кривая реализация встроенной функции gcc __atomic_store_n для данной маргинальной платформы. Собственно тут (https://github.com/michaeljclark/riscv-atomics) можно увидеть две реализации и та, что на сайте godbolt, использует именно кривой вариант через встроенную функцию gcc, а не через ассемблер. Нормальную реализацию можно увидеть например здесь https://github.com/michaeljclark/riscv-atomics/blob/master/src/stdatomic_asm.h#L95. И подробное обсуждение всей этой кривизны можно увидеть здесь https://github.com/michaeljclark/riscv-atomics/tree/master/results.
·>Ок, ты в очередной раз подменяешь тезис. Но пусть кривая. В любом случае, она ничему не противоречит и имеет право на жизнь. Возможно лишь ухудшает перформанс.
·>И уж тем более это никак не доказывает, что volatile sig_atomic можно использовать в многопоточке. Доказательством будет фраза в стандарте. А стандарт наоборот это явно запрещает.

1. Я не пытаюсь что-то доказать, т.к. факт атомарности записи регистра в память общеизвестен (мне вообще странно, что ты начал об этом спорить).
2. Что-то доказать пытаешься тут ты, причём весьма странным способом — пытаясь найти реализацию std::atomic, в которой операция записи реализовывалась бы не через стандартные инструкции записи. Хотя очевидно, что даже если бы ты вдруг такое и нашёл, это не стало бы доказательство неатомарности обычных инструкций.
3. Стандарт вообще ничего не запрещает. )))
4 (главное — надеюсь хотя сейчас до тебя это дойдёт). Когда ты где-то видишь фразу типа того что атомарность sig_atomic (читай int'а) является достаточной для сигналов, но недостаточной для потоков, то это идёт речь об атомарности в широком смысле (включая гарантии отсутствия переупорядочивания инструкций, который даёт std::atomic с дефолтными настройками). Если же говорить об атомарности в чистом виде (именно в таком мы её и обсуждали, причём по именно твоему определению), то никакой разницы между сигналами, потоками или чем-то ещё просто нет. Ну и да, sig_atomic + вызов atomic_thread_fence(memory_order_seq_cst) при каждом обращение даст тебе атомарность даже в широком смысле (и для сигналов и для потоков), но это к теме нашей дискуссии уже не относится.
Re[49]: Безопасность Rust
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.06.19 14:26
Оценка: +1
Здравствуйте, vdimas, Вы писали:

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

"До этого" это до чего?
V>Но это же не означает, что не существовало языка?

V>Поэтому, твои попытки привязать появление этого ключевого слова к дате стандарта — это ж залёт, курсант! ))
Момент в дискуссии, когда вы переходите от осознания ошибки к панике, всегда можно определить по выделенной фразе

V>Там в годы разница, а не в месяцы.

Совершенно верно, в годы.

V>Это утверждение не позволяет подтверждать или опровергать мысль о том, что компилятор с 67-го года не развивался.

Конечно, развивался. Мы неплохо знаем о том, как был устроен AT&T шный компилятор начала 80х, из публикаций его автора

V>Это никак не отменяет твоей попытки приписать оппоненту некую удобную тебе мысль.

Отож. То есть 15 лет подряд разработка UNIX шла как по маслу без volatile, и вдруг в середине 80х произошёл внезапный перелом. Тем не менее, volatile является "артефактом тех времён, когда C разрабатывался для целей разработки многозадачной операционки UNIX

V>Сначала соглашаешься с тем, что необходимость volatile для UNIX возникла, хоть и не сразу, но в другом предложении ты утверждаешь, что не возникла, оказывается.

Не, так и не возникла.

V>Какой "этой ниши"?

Ниши "разработка операционок".


S>>Cовременный взгляд на применение volatile "для целей операционки" вам изложить, или вы его и так знаете?


V>Давай я тебя подстрахую от надобности затем натягивать очередных сов на глобусы или наоборот: современный взгляд можно почерпнуть из исходников Linux, например.


Я бы больше поверил словам самого Линуса, чем результатам поиска в гитхабе
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[38]: Безопасность Rust
От: · Великобритания  
Дата: 04.06.19 15:05
Оценка:
Здравствуйте, alex_public, Вы писали:

_>·>Ок, ты в очередной раз подменяешь тезис. Но пусть кривая. В любом случае, она ничему не противоречит и имеет право на жизнь. Возможно лишь ухудшает перформанс.

_>·>И уж тем более это никак не доказывает, что volatile sig_atomic можно использовать в многопоточке. Доказательством будет фраза в стандарте. А стандарт наоборот это явно запрещает.
_>1. Я не пытаюсь что-то доказать, т.к. факт атомарности записи регистра в память общеизвестен (мне вообще странно, что ты начал об этом спорить).
Факт в том, что обычно платформы реализуют это именно так. Но это ни к чему не обязывает. Мало того, этот факт не имеет никакого отношения к С/С++.

_>2. Что-то доказать пытаешься тут ты, причём весьма странным способом — пытаясь найти реализацию std::atomic, в которой операция записи реализовывалась бы не через стандартные инструкции записи. Хотя очевидно, что даже если бы ты вдруг такое и нашёл, это не стало бы доказательство неатомарности обычных инструкций.

Я просто повёлся.

_>3. Стандарт вообще ничего не запрещает. )))

Он называет это undefined behaviour.

_>4 (главное — надеюсь хотя сейчас до тебя это дойдёт). Когда ты где-то видишь фразу типа того что атомарность sig_atomic (читай int'а) является достаточной для сигналов, но недостаточной для потоков, то это идёт речь об атомарности в широком смысле (включая гарантии отсутствия переупорядочивания инструкций, который даёт std::atomic с дефолтными настройками). Если же говорить об атомарности в чистом виде (именно в таком мы её и обсуждали, причём по именно твоему определению), то никакой разницы между сигналами, потоками или чем-то ещё просто нет. Ну и да, sig_atomic + вызов atomic_thread_fence(memory_order_seq_cst) при каждом обращение даст тебе атомарность даже в широком смысле (и для сигналов и для потоков), но это к теме нашей дискуссии уже не относится.

Напоминаю. Разговор начался с твоего кода присвоения "int global_var" и мой тезис был с "Если это же сделать многопоточным, т.е. эту global_var будут пытаться писать одновременно разные потоки без всякой синхронизации, то возможен data race и значение global_var может быть каким угодно."
Потом ты начал подменять тезис, изменяя int на sig_atomic, потом ещё volatile, потом маш-коды, теперь ты наконец-то дошел до atomic_thread_fence. Похоже, ты во всём разобрался. Можно сворачивать разговор.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[35]: Безопасность Rust
От: alex_public  
Дата: 04.06.19 16:35
Оценка:
Здравствуйте, ·, Вы писали:

_>>·>1. Safe rust даёт гарантии от data race.

_>>Прежде чем согласиться или нет, надо в начале определить что такое "Safe rust". А то я что-то не помню официального определения. Единственное чётко формулируемое (причём даже на уровне компилятора), это "код в котором нет вызовов unsafe кода". Но как ты знаешь, при таком определение safe rust тебе банально даже не удастся завести в нём многопоточность (потому как те же Mutex и т.п. внутри unsafe). Т.е. я подозреваю, что подразумевается какое-то иное определение — озвучь его.
·>Код, который использует safe-конструкции. Примечание: наличие ключевого слова "unsafe" автоматически не означает что данная конструкция перестаёт быть safe, т.к. safety может быть доказана отдельно (вручную человеком, например).

Ааа, т.е. safe код — это такой код, в котором встречаются только куски safe кода? Ясно, понятно. )))

Кстати, хочу тогда заметить, что safe assembler даёт гарантии не только от data race, но и ещё много от чего!

_>>·>2. Доступ через volatile не является atomic.

_>>Модификатор volatile вообще никак не связан с атомарностью. Т.е. через него могут быть определены как атомарные объекты, так и нет.
·>Ок. Сформулирую поточнее. "volatile sig_atomic_t" — не является atomic с т.з. многопоточности.

Является атомарным (в значение атомарности, определённом в нашей дискуссии выше) и в сигнала и в потоках и где угодно.

_>>·>3. Конкурентный доступ из разных потоков к volatile является data race.

_>>Для начала надо определить что такое "доступ" (какие операции конкретно)
·>Как минимум одна операция записи и ещё одна операция чтения-или-записи.
_>>и к каким конкретно типам (volatile же это модификатор, а не тип).
·>"volatile sig_atomic_t"
_>>Для определённых операций (типа записи/чтения) и определённых типов данных (помещающихся в регистр целевой архитектуры) гонок не будет. А для других случаев будут.
·>Ссылку на стандарт в студию.

Не является data race согласно твоему же определению выше в теме (по которому в случае атомарного доступа у нас не data race, а "недетерминизм").
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.