Не по порядку пишет без барьера памяти: единственная возможная причина гонки данных?

При изучении Java Concurrency by Brian Goetz на практике я наткнулся на следующую строку:

Гонка данных происходит, когда переменная читается более чем одним потоком и записывается как минимум одним потоком, но операции чтения и записи не упорядочены по принципу «происходит до». В правильно синхронизированной программе нет гонок данных; правильно синхронизированные программы демонстрируют последовательную согласованность, что означает, что все действия в программе происходят в фиксированном глобальном порядке.

Мой вопрос заключается в том, что Is Out of Order пишет единственную причину состояния гонки данных в java или, возможно, в других языках программирования?
ОБНОВЛЕНИЕ
Хорошо, я провел дополнительное исследование данных. race и нашел следующее на официальном сайте oracle в котором говорится, что:

Анализатор потоков обнаруживает гонки данных, возникающие во время выполнения многопоточного процесса. Гонка данных возникает, когда:

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

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


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


person Mac    schedule 05.07.2014    source источник
comment
Я думаю, что это в значительной степени определение гонки данных, да.   -  person biziclop    schedule 06.07.2014
comment
@biziclop: Спасибо за ваш ответ. Это означает, что, скажем, несколько потоков обращаются только к одной переменной, и один из потоков записывает эту переменную атомарно, в то время как остальные потоки обращаются к ней одновременно, тогда не может быть никаких состояние гонки данных там?   -  person Mac    schedule 06.07.2014
comment
Да может. Проблема в видимости памяти. Если вы не пометили переменную как volatile или не защитили доступ к ней с помощью синхронизированного блока или блокировки, возможно, что данный поток не увидит обновления, сделанные другим потоком.   -  person Brett Okken    schedule 06.07.2014
comment
@BrettOkken: Спасибо. Означает ли это, что гонка данных связана с атомарностью, последовательностью (порядка кодов в блоке кода, выполняемого потоками не выполнения потоков), а также с видимостью? Если все это реализовано правильно, то в этом коде не может быть состояния гонки данных?   -  person Mac    schedule 06.07.2014
comment
@Mac: ключом является атомарная запись в эту переменную. Атомарные операции, поддерживаемые Java (например, java.util.concurrent.atomic.*), гарантируют, что операции упорядочены. Таким образом, если один поток обновляет атомарную переменную, обновление происходит до всех последующих операций чтения. Сама атомарная операция устанавливает барьер памяти. Если вы не можете обновить переменную атомарно (или с синхронизацией или блокировками), то могут произойти случаи, подобные упомянутым в комментарии @BrettOkken.   -  person James    schedule 06.07.2014
comment
docs.oracle.com/ javase/specs/jls/se8/html/   -  person Alex - GlassEditor.com    schedule 06.07.2014
comment
@Mac: все дело в барьере памяти. Атомарная операция, видимость, синхронизация и блокировки связаны с установкой барьера памяти, чтобы операции с определенными блоками данных имели правильную семантику упорядочения.   -  person James    schedule 06.07.2014
comment
Люди, которые голосуют за закрытие этого вопроса, пожалуйста, оставьте свой комментарий, чтобы я мог знать, почему вы думаете, что я не понимаю, о чем я спрашиваю здесь. Если вам нужны какие-либо разъяснения по этому вопросу, спросите меня. Я буду более чем счастлив разъяснить озабоченность, которую я хочу затронуть в этом вопросе.   -  person Mac    schedule 06.07.2014
comment
Нам нужно быть осторожными, говоря об атомарных операциях. Установка любого примитива (кроме double или long) является атомарной. Это не означает, что он виден через потоки.   -  person Brett Okken    schedule 06.07.2014
comment
@BrettOkken: Спасибо, что обратили внимание на этот момент. Я думаю, что атомарную настройку double и long можно разрешить, объявив их как volatile.   -  person Mac    schedule 06.07.2014
comment
И пометка их как изменчивых также создает барьер памяти и устанавливает отношения перед отношениями (как и с любым другим типом данных, помеченным как изменчивым).   -  person Brett Okken    schedule 06.07.2014
comment
Брайан Гетц: В правильно синхронизированной программе нет гонок данных. Oracle: Некоторые гонки данных могут быть безобидными. Эти два источника по-разному определяют гонку данных. Определение Oracle шире. Существует множество способов чередования операций, выполняемых потоками большой многопоточной программы. Oracle говорит, что существует гонка данных, когда разные чередования могут привести к разным результатам. Гетц называет это гонкой данных только тогда, когда некоторые чередования приводят к неправильному выводу (включая сбои, повреждение данных или, возможно, просто отдельные неправильные ответы).   -  person Solomon Slow    schedule 06.07.2014
comment
@jameslarge Эти два не обязательно противоречат друг другу. Некоторые гонки данных действительно могут быть безобидными, но программа все равно будет классифицироваться как некорректно синхронизированная.   -  person biziclop    schedule 06.07.2014
comment
@Mac Люди, которые голосуют за закрытие этого вопроса, явно придерживаются мнения, что, если они этого не понимают, это не имеет никакого смысла. К сожалению, в SO слишком много таких людей. Ваш вопрос, конечно, совершенно ясен и актуален.   -  person biziclop    schedule 06.07.2014
comment
Я думаю, что как в этом вопросе, так и в комментариях много путаницы. В частности, понятие недетерминированного порядка доступа различных потоков (который всегда присутствует) путают с нарушением причинно-следственной связи между действиями потоков.   -  person Marko Topolnik    schedule 06.07.2014
comment
Сам вопрос также содержит запутанные предположения: Is Out of Order writes the only reason for Data Race condition? Запись вне очереди происходит с гонками данных или без них. Они определенно не являются причиной для гонок данных; однако наличие гонок данных означает, что неупорядоченные записи могут наблюдаться другими потоками, что нарушает причинно-следственную связь.   -  person Marko Topolnik    schedule 06.07.2014
comment
Таким образом, вопрос должен заключаться в том, опасны ли гонки данных только из-за неупорядоченной записи? и ответ на этот: нет, есть и много других причин, таких как пишет, что не происходит вообще. Значение энергонезависимой переменной может быть скопировано в стек, и все последующие записи внутри метода будут выполняться в этой копии.   -  person Marko Topolnik    schedule 06.07.2014
comment
@MarkoTopolnik: Спасибо, что высказали свое мнение по этому вопросу. Но, как вы можете видеть, в вопросах я расставил слова точно так, как сказано в книге Гонка данных возникает, когда переменная читается более чем одним потоком и записывается хотя бы одним потоком, но чтение и запись не упорядочены по событию-прежде. Я думаю, здесь ясно упоминается, что если чтение и запись не упорядочены по событию-до, то возникнет состояние гонки. Пожалуйста, поправьте меня, если я ошибаюсь: не по порядку пишет - единственный виновник, который несет ответственность за несоблюдение того, что происходит до отношений.   -  person Mac    schedule 06.07.2014
comment
@MarkoTopolnik: как вы упомянули в своем комментарии, запись не по порядку происходит с гонками данных или без них. Однако я спрашиваю об обратном: происходит ли гонка данных с записью вне порядка или без нее?   -  person Mac    schedule 06.07.2014
comment
Вы путаете уровни описания: упорядочение по происходит до является 1) статическим свойством программы и 2) более абстрактным, чем понятие записи не по порядку. Программа может содержать гонку данных, даже если при ее выполнении не происходит записи не по порядку.   -  person Marko Topolnik    schedule 06.07.2014
comment
@MarkoTopolnik: Тогда какова настоящая причина гонки данных в Java? И что приводит к тому, что чтение и запись не упорядочены раньше?   -  person Mac    schedule 06.07.2014
comment
Ну, это то, что четко указывает JLS. Вы читали главу о модели памяти, не так ли?   -  person Marko Topolnik    schedule 06.07.2014
comment
Как упоминалось в JLS о гонке данных: Когда программа содержит два конфликтующих доступа (§17.4.1), которые не упорядочены отношением «происходит до», говорят, что она содержит гонку данных. И о происходит перед отношением : Два действия могут быть упорядочены по событию-до: если одно действие происходит-перед другим, то первое видно и упорядочено перед вторым.. В конечном счете гонка данных сводится к тому, что происходит до того, как порядок. И, насколько я понимаю, для двух действий x и y, если x происходит до y, тогда любой (поток) после прочтения действия y также должен увидеть действие x. Я прав?   -  person Mac    schedule 06.07.2014
comment
Да это правильно. Это о причинно-следственной связи. И статическое свойство правильно синхронизированной программы заключается в том, что все конфликтующие действия между потоками будут некоторыми происходить до того, как будут упорядочены между ними. Что именно произойдет раньше, чем другое, конечно, недетерминировано.   -  person Marko Topolnik    schedule 07.07.2014
comment
Спасибо @MarkoTopolnik: Теперь, если я правильно зашел так далеко в понимании того, что происходит, до этого позвольте мне сделать снимок того, что я понял о гонке данных: не по порядку записи произошли в коде. Это правильно? Также, если вы посмотрите в JLS эту строку Таблица 17.2. Удивительные результаты, вызванные изменением порядка операторов — действительное преобразование компилятора . Чуть ниже написано, что Эта ситуация является примером гонки данных   -  person Mac    schedule 07.07.2014
comment
Нет, шаг от того, что не происходит — до того, как заказать, к тому, что пишет не по порядку, не так уж и прост. Во-первых, могла быть только одна запись, так что ясно, что она не может быть не в порядке сама с собой; еще один поток может никогда не наблюдать это без события-до. Во-вторых, записи не по порядку могут вообще не происходить, они просто становятся разрешенными JLS. В-третьих, как я упоминал ранее, может случиться много других вещей, которые не сводятся к записи не по порядку, например, к полному отсутствию записи.   -  person Marko Topolnik    schedule 07.07.2014
comment
@MarkoTopolnik: Итак, исходя из этого, могу ли я понять последовательность таким образом: data-race=›происходит-прежде чем заказ не выполняется=› произошло либо несколько, либо все из следующего: 1. вне- заказ пишет 2. локальный кеш-поток не обновляется 3. записи до сих пор не было.   -  person Mac    schedule 07.07.2014
comment
Гонка данных существует в программе по определению. На самом деле ничего плохого не должно произойти, а в наивной реализации JVM ничего не произойдет --- выполнение может происходить последовательно согласованным образом, и никакие действия между потоками не будут восприниматься не по порядку даже в программе, полностью лишенной какой-либо синхронизации.   -  person Marko Topolnik    schedule 07.07.2014
comment
@MarkoTopolnik Спасибо за ваши усилия, которые вы приложили, чтобы прояснить концепцию Data Race. Не могли бы вы поделиться своим мнением и по моему следующему вопросу: " title="почему принцип подстановки лисков требует, чтобы аргумент был контравариантным"> stackoverflow.com/questions/40340317/   -  person Mac    schedule 31.10.2016


Ответы (1)


Я бы скорее определил гонку данных как

Гонка данных между записью и чтением некоторого значения или ссылки из переменной — это ситуация, когда результат чтения определяется «внутренним» (управляемым jvm или os) планированием потоков.

Фактически, второе определение из вопроса говорит то же самое более «официальными» словами :)

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

Теперь на ваш вопрос:

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

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

О порядке доступа: он будет детерминированным с синхронизацией следующим образом:

Давайте еще раз взглянем на наши потоки A и B. Порядок операций теперь последовательный — поток B не сможет начать чтение, пока поток A не закончит запись. Чтобы прояснить эту ситуацию, представьте, что письмо и чтение — это действительно длительный процесс. Без синхронизации эти операции могут пересекаться друг с другом, что может привести к чтению некоторых бессмысленных значений.

person Alexey Malev    schedule 28.11.2014