Информация об изменениях

Сообщение Re[25]: Безопасность Rust от 29.05.2019 12:49

Изменено 29.05.2019 12:58 alex_public

Re[25]: Безопасность Rust
Здравствуйте, ·, Вы писали:

_>> global_var=await process_asyc(global_var, param);//process_asyc — длительная асинхронная операция

_>>Так вот, надеюсь не надо пояснять, почему результат работы этого теперь уже некорректного кода будет зависеть от случайных факторов? При этом вся работа с проблемной переменной будет происходить исключительно в рамках одного потока...
·>Ок, хороший пример, давай я помогу тебе разобраться. В случае однопоточного асинхронного исполнения будет race condition, и в итоге результат выполнения будет недетерминирован, но не являться undefined behaviour. Недерминированность выражается в том, что значение global_var будет одним из значений process, но неясно каким из.
·>Если это же сделать многопоточным, т.е. эту global_var будут пытаться писать одновременно разные потоки без всякой синхронизации, то возможен data race и значение global_var может быть каким угодно.
·>Принципиальная разница в том, что в случае недетерминизма мы можем анализировать код и делать какие-то заключения (reasoning) о поведении данной части кода и программы в целом, то в случае наличия UB — мы можем сказать лишь одно: behavior of the program is undefined.
·>Например, допустим мы знаем, что process возвращает только положительные числа.
·>В случае недетерминизма, мы можем смело утверждать, что global_var будет положительным числом.
·>В случае же undefined behaviour — в переменной может оказаться всё что угодно, никаких гарантий нет. Притом этот результат может зависеть от версии компилятора, от железа, от операционки, от погоды на марсе и т.п.
·>Кстати, если присвоение global_var будет атомарным, то опять получится недетерминизм, а не undefined behaviour.

Значит по тезисам:
1. В данном конкретном примере присвоение global_var как раз будет атомарным. Потому как это int и C++ следит за выравниванием. Как это будет происходить на низком уровне скажем в процессорах Intel можешь глянуть например здесь https://software.intel.com/en-us/articles/software-techniques-for-shared-cache-multi-core-systems в пункте Avoid false sharing.
2. Так что поведение в асинхронном и многопоточном варианте будет абсолютно идентично.
3. Undefined behaviour очевидно не является определением data race, а является всего лишь следствием.
4. Насколько я вижу, вся эта дискуссия с тобой свелась к спору о терминологии, что весьма глупо. Лично мне абсолютно всё равно как называть конкретные явления, лишь бы договорить об одном языке для всех. Я могут сформулировать свою мысль в любой терминологии — мой основной тезис вообще не зависит от данного выбора.
5. Ну и наконец тот самый главный тезис: как ни называй описанную проблему, Rust никак от неё не защищает.

_>>·>В случае конкурентного чтения и записи, например, атомарость говорит о том, что читатель увидит либо старое значение, до записи, либо новое, после записи и ничто другое. Да, атомарность нужна для интов.

_>>Правильно. Только вот ассемблерная инструкция перемещения регистра в память (что равносильно оператору равенства в твоём языке программирования) является вполне себе атомарной,
·>Для какого CPU? А про membar-ы не забыл?

Ну если ты знаешь CPU, в котором перемещение регистра в ячейку памяти (естественно подразумеваем выровненную, что является нормой) является не атомарным, то с удовольстием послушаю про такой. )))

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

_>>так что для int'ов(подразумевая под ним машинное слово) оно и так автоматически имеется.

·>Если бы С++/Rust/etc стандарт писался ровно для одного CPU и т.п., то возможно твоё утверждение было бы и верным.

Ну приведи хоть один контрпример. )))

_>>Поэтому для ограниченного числа задач на самом деле можно параллельно обращаться к одному int'у и всё будет нормально.

·>"А у меня всё работаииит!"

На самом деле на многих ещё актуальных аппаратных платформах просто нет специальных атомарных инструкций, как ты думаешь, как там выживают? )))

_>>Проблема возникает если надо использовать корректное предыдущее значение — тогда на помощь приходит CAS.

·>А так же проблема возникает ещё в 100500 случаев, например, если этот конкретный int вдруг невыровненный оказался.

Ну скажем в C++ он просто так невыровненным не окажется — у нас полный контроль за этим. )))

_>>Кстати, по этой ссылке дальше идёт ещё более интересный текст про многопоточность в Rust в общем. Что никаких гарантий естественно нет и единственно чем реально озабочем тут Rust, это сохранение memory safety — как я собственно и говорил изначально.

·>Там про race condition.

И? О того что ты назовёшь это по другому, у тебя некорректный код вдруг заработает правильно? )))
Re[25]: Безопасность Rust
Здравствуйте, ·, Вы писали:

_>> global_var=await process_asyc(global_var, param);//process_asyc — длительная асинхронная операция

_>>Так вот, надеюсь не надо пояснять, почему результат работы этого теперь уже некорректного кода будет зависеть от случайных факторов? При этом вся работа с проблемной переменной будет происходить исключительно в рамках одного потока...
·>Ок, хороший пример, давай я помогу тебе разобраться. В случае однопоточного асинхронного исполнения будет race condition, и в итоге результат выполнения будет недетерминирован, но не являться undefined behaviour. Недерминированность выражается в том, что значение global_var будет одним из значений process, но неясно каким из.
·>Если это же сделать многопоточным, т.е. эту global_var будут пытаться писать одновременно разные потоки без всякой синхронизации, то возможен data race и значение global_var может быть каким угодно.
·>Принципиальная разница в том, что в случае недетерминизма мы можем анализировать код и делать какие-то заключения (reasoning) о поведении данной части кода и программы в целом, то в случае наличия UB — мы можем сказать лишь одно: behavior of the program is undefined.
·>Например, допустим мы знаем, что process возвращает только положительные числа.
·>В случае недетерминизма, мы можем смело утверждать, что global_var будет положительным числом.
·>В случае же undefined behaviour — в переменной может оказаться всё что угодно, никаких гарантий нет. Притом этот результат может зависеть от версии компилятора, от железа, от операционки, от погоды на марсе и т.п.
·>Кстати, если присвоение global_var будет атомарным, то опять получится недетерминизм, а не undefined behaviour.

Значит по тезисам:
1. В данном конкретном примере присвоение global_var как раз будет атомарным. Потому как это int и C++ следит за выравниванием. Как это будет происходить на низком уровне скажем в процессорах Intel можешь глянуть например здесь https://software.intel.com/en-us/articles/software-techniques-for-shared-cache-multi-core-systems в пункте Avoid false sharing.
2. Так что поведение в асинхронном и многопоточном варианте будет абсолютно идентично.
3. Undefined behaviour очевидно не является определением data race, а является всего лишь следствием.
4. Насколько я вижу, вся эта дискуссия с тобой свелась к спору о терминологии, что весьма глупо. Лично мне абсолютно всё равно как называть конкретные явления, лишь бы договорить об одном языке для всех. Я могут сформулировать свою мысль в любой терминологии — мой основной тезис вообще не зависит от данного выбора.
5. Ну и наконец тот самый главный тезис: как ни называй описанную проблему, Rust никак от неё не защищает.

_>>·>В случае конкурентного чтения и записи, например, атомарость говорит о том, что читатель увидит либо старое значение, до записи, либо новое, после записи и ничто другое. Да, атомарность нужна для интов.

_>>Правильно. Только вот ассемблерная инструкция перемещения регистра в память (что равносильно оператору равенства в твоём языке программирования) является вполне себе атомарной,
·>Для какого CPU? А про membar-ы не забыл?

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

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

_>>так что для int'ов(подразумевая под ним машинное слово) оно и так автоматически имеется.

·>Если бы С++/Rust/etc стандарт писался ровно для одного CPU и т.п., то возможно твоё утверждение было бы и верным.

Ну приведи хоть один контрпример. ))) Любой CPU, в котором это не так.

_>>Поэтому для ограниченного числа задач на самом деле можно параллельно обращаться к одному int'у и всё будет нормально.

·>"А у меня всё работаииит!"

На самом деле на многих ещё актуальных аппаратных платформах просто нет специальных атомарных инструкций, как ты думаешь, как там выживают? )))

_>>Проблема возникает если надо использовать корректное предыдущее значение — тогда на помощь приходит CAS.

·>А так же проблема возникает ещё в 100500 случаев, например, если этот конкретный int вдруг невыровненный оказался.

Ну скажем в C++ он просто так невыровненным не окажется — у нас полный контроль за этим. )))

_>>Кстати, по этой ссылке дальше идёт ещё более интересный текст про многопоточность в Rust в общем. Что никаких гарантий естественно нет и единственно чем реально озабочем тут Rust, это сохранение memory safety — как я собственно и говорил изначально.

·>Там про race condition.

И? О того что ты назовёшь это по другому, у тебя некорректный код вдруг заработает правильно? )))