Пример правильно синхронизированной программы с гонками данных в модели памяти Java

В JLS, §17.4.5. "Случается перед заказом", в нем говорится, что

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

Согласно обсуждению в Есть ли правильно ли синхронизированная программа по-прежнему допускает гонку данных? (Часть I), мы получаем следующий вывод:

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

Сочетание двух выводов означает, что должен существовать такой пример:

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

После долгих размышлений я все еще не могу найти такой образец кода. Так как насчет тебя?


person newman    schedule 19.08.2012    source источник
comment
В книге «Параллелизм Java на практике» есть весь этот код для вас. см. jcip.net   -  person su-    schedule 19.08.2012
comment
@newman +1 за правильное исследование вашего вопроса!   -  person obataku    schedule 19.08.2012
comment
@ su-, не могли бы вы указать, какой код в этой книге может удовлетворить мою просьбу.   -  person newman    schedule 19.08.2012
comment
@newman Я не пришел к выводу, что программа может быть правильно синхронизирована и иметь гонку данных. Я только показал вам, что программа может иметь все свои исполнения последовательно согласованными и иметь гонку данных.   -  person assylias    schedule 20.08.2012
comment
String - действительно интересный пример, класс является потокобезопасным и содержит гонку данных в hashCode (). Несмотря на то, что класс не имеет никакой синхронизации и содержит изменяемые данные, он по-прежнему является потокобезопасным. Эта гонка данных является благоприятной, потому что объект String не меняет того, кто выиграет гонку.   -  person Mark    schedule 20.08.2012


Ответы (1)


Неверно, что программа может быть правильно синхронизирована и иметь гонку данных. Пример от assylias в этом обсуждении неправильно синхронизирован. Это правильно с функциональной точки зрения более высокого уровня - содержащаяся в нем гонка данных не проявляется как ошибка. Это так называемая «мягкая гонка данных», но это не имеет отношения к обсуждению определений JLS.

Программа, последовательное согласованное выполнение которой не содержит гонок данных, гарантированно не будет содержать гонок данных при любом выполнении, последовательном или непротиворечивом. Как говорится в JLS,

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

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

ОБНОВИТЬ

Легко заблудиться в терминологии, используемой JMM, и тонкие неверные истолкования приводят в дальнейшем к глубоким недоразумениям. Поэтому примите это близко к сердцу:

  • выполнение - это просто набор межпотоковых действий. Для этого нет априорного порядка. В частности, для него нет временного порядка.

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

  • программа содержит инструкции по выполнению действий. Каждая такая инструкция может выполняться ноль или более раз, что вносит ноль или более различных действий в конкретное выполнение;
  • выполнение может иметь или не иметь порядок выполнения, который представляет собой общий порядок для всех действий;
  • последовательное согласованное выполнение - это то, что вы получили бы, если бы все ваши общие переменные были непостоянными. Этот вид исполнения всегда имеет определенный порядок исполнения;
  • последовательное несогласованное выполнение - это ваше реальное выполнение программы: задействованы энергонезависимые переменные, и компилятор переупорядочивает операции чтения и записи, есть кеши, локальные хранилища потоков , так далее.
  • порядок синхронизации - это общий порядок всех действий синхронизации, выполняемых при выполнении. Что касается самого выполнения, это все еще частичный порядок, потому что не все действия являются действиями синхронизации; в первую очередь, чтение и запись энергонезависимых переменных. Каждое выполнение, независимо от того, является ли оно последовательным или нет, имеет определенный порядок синхронизации;
  • аналогично, порядок происходит до определяется для конкретного выполнения программы и выводится как транзитивное замыкание порядка синхронизации с порядком программы.

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

Я глубоко копнул, чтобы разобраться в ошибке JLS в определении гонки данных:

Когда программа содержит два конфликтующих доступа (§17.4.1), которые не упорядочены отношением происходит до, говорят, что она содержит гонку данных.

Прежде всего, это не программа, которая содержит гонку данных, а выполнение программы. Если мы вернемся к исходной статье, определяющей модель памяти Java, мы Увидим это исправленным:

Два доступа x и y образуют гонку данных при выполнении программы, если они из разных потоков, они конфликтуют и не упорядочиваются случается- до.

Однако это по-прежнему оставляет нам действия с изменчивыми варами, определяемыми как гонки данных. Рассмотрим следующий график произошло до:

Thread W        w1 ----> w2
                |
                 \
Thread R     r0 ----> r1

r1 наблюдал за записью w1. Ему предшествовало другое чтение, r0, а за записью последовало другое чтение, w2. Теперь обратите внимание, что нет пути между r0 и w1 или w2; аналогично между r1 и w2. Все это по определению примеры гонки данных.

Однако, копнув еще глубже, я нашел этот пост на Список рассылки memoryModel. В нем говорится, что гонка данных должна определяться как конфликтующие действия с энергонезависимыми переменными, которые не упорядочены по принципу «произошло раньше». Только с этим дополнением лазейка будет закрыта, но это еще не вошло в официальный релиз JLS.

person Marko Topolnik    schedule 19.08.2012
comment
Если программа может быть правильно синхронизирована и иметь скачки данных. неверно, тогда мы получаем Если программа правильно синхронизирована, то она свободна от гонок данных. Но от JLS мы не можем получить такой вывод. Другими словами, если второй вывод верен, то JLS покажет нам, а JLS - нет. - person newman; 19.08.2012
comment
Когда программа содержит два конфликтующих доступа (§17.4.1), которые не упорядочены отношением происходит до, говорят, что она содержит гонку данных. Обратите внимание, что происходит до не определено для программы, а для одного из ее выполнения. Это просто слабая формулировка JLS. В действительности это предложение относится к выполнению программы. Затем обратите внимание, что вы можете изменить порядок выполнения как хотите, не нарушая отношения происходит до. Следовательно, вы не можете вызвать гонку данных, переупорядочивая последовательно согласованное выполнение в несогласованное. - person Marko Topolnik; 19.08.2012
comment
У меня два момента по поводу вашего ответа: 1. вы все еще не отвечаете на мой вопрос, почему JLS не говорит: Если программа правильно синхронизирована, то в ней нет гонок данных. 2. Изменение порядка выполнения любым способом может нарушить отношения «происходит до», если вы измените порядок выполнения действий, которые имеют отношение «происходит до». - person newman; 19.08.2012
comment
1. Это первый раз, когда вы спрашиваете об этом так неудивительно, что я не отвечаю на него. 2. Случаи-до не определены с точки зрения порядка исполнения. - person Marko Topolnik; 19.08.2012
comment
По 1. Обратите внимание, что гонка данных определяется не для программы, а для конкретного выполнения этой программы. - person Marko Topolnik; 19.08.2012
comment
Я хотел бы спросить вас следующее: понимаете ли вы, в чем заключается различие между последовательным и непоследовательным выполнением программы? Понимаете ли вы, что разница заключается не в контроле программы (таким образом, вы как программист), а в реализации JVM? Вы не можете запросить программу, которая демонстрирует последовательное несогласованное выполнение, или программу, чье последовательное несовместимое выполнение содержит гонку данных. Эти вопросы бессмысленны. - person Marko Topolnik; 20.08.2012
comment
@MarkoTopolnik re гонка данных не определена для программы, цитируя JLS: Когда программа содержит два конфликтующих доступа (§17.4.1), которые не упорядочены отношениями «происходит раньше», говорят, что он содержит гонку данных. - person assylias; 20.08.2012
comment
@assylias Да, я уже обсуждал этот вопрос с OP. Это пример, к сожалению, слабой формулировки в JLS, но поскольку в другом месте происходит-до определяется в терминах порядка синхронизации, и это снова определяется только для конкретного выполнения , должно быть, что на самом деле имеется в виду выполнение программы. - person Marko Topolnik; 20.08.2012
comment
Я понимаю это как ярлык: программа свободна от гонки данных (DRF) ‹=› все ее исполнения - DRF. - person assylias; 20.08.2012
comment
@assylias Это то, что мы обычно предполагаем под этим понятием, но OP переходит к JLS и читает. Программа правильно синхронизирована тогда и только тогда, когда все последовательные согласованные выполнения свободны от гонок данных. и начинает беспокоиться, но как насчет последовательно несовместимых казней? NB. Я думаю, что OP действительно хочет, чтобы термины были на 100% ясны, прежде чем позволять себе использовать ярлыки. - person Marko Topolnik; 20.08.2012
comment
@newman Я провел еще несколько исследований по этой проблеме с определением гонки данных. Подробности см. В обновленном ответе. - person Marko Topolnik; 21.08.2012
comment
@assylias Исправить это определение гонки данных оказалось сложнее, чем просто заменить программу выполнением: даже после этого любая программа, включающая изменчивые переменные, будет определяться как содержащая гонку данных. Смотрите мое обновление в этом ответе для получения интересных подробностей. - person Marko Topolnik; 21.08.2012
comment
@Marko Topolnik, большое спасибо за вашу работу. но меня все еще беспокоит вопрос. Вы сказали, что «происходит до» не определяется в терминах порядка выполнения. Теперь давайте посмотрим на определение «происходит до»: ... • Если действие x синхронизируется со следующим действием y, то у нас также есть hb (x, y) .... Теперь продолжим наш взгляд на определение синхронизируется с: ... • Действие разблокировки на мониторе m синхронизируется со всеми последующими действиями блокировки на m (где последующее определяется в соответствии с синхронизацией порядок) .... Теперь продолжим рассмотрение определения синхронизации. - person newman; 21.08.2012
comment
порядок: порядок синхронизации - это общий порядок всех действий синхронизации выполнения. Теперь мы можем сделать вывод: случится-до, по крайней мере, частично определяется с точки зрения порядка выполнения. Вот почему я сказал, что изменение порядка выполнения каким-либо образом может нарушить отношения «происходит до», если вы измените порядок выполнения действий, которые имеют отношение «происходит до»., В большей степени это должно быть: ... если вы измените порядок выполнения действий, которые имеют отношение "происходит до", которое определяется в порядке синхронизации. - person newman; 21.08.2012
comment
Там я добавил пояснение ключевых терминов. Прочтите его и посмотрите, проясняет ли он ваши мысли. - person Marko Topolnik; 21.08.2012
comment
@MarkoTopolnik Это действительно становится очень точным - извините, я не могу +2 вам! Однако я считаю, что нам следует придерживаться здравого смысла в отношении семантика volatile (которая не поддерживается JLS) для большинства вопросов SO. Этот пост, по общему признанию, отличается, поскольку OP специально запрашивает терминологию. - person assylias; 21.08.2012
comment
@assylias Да, особенно потому, что это общепризнанная ошибка JLS. Кроме того, в любом контексте, кроме этого уровня точности, «последовательная согласованность» является синонимом создания видимости последовательной согласованности. Поскольку фактическая последовательная последовательность никогда не достигается, это создает своего рода вакансию для полезного значения термина. - person Marko Topolnik; 21.08.2012
comment
@assylias, не могли бы вы сказать мне, что значит ТАК в вашем ответе ... на большинство ТАКИХ вопросов? Большое спасибо. - person newman; 22.08.2012
comment
@MarkoTopolnik. Я не уверен, улавливаю ли я смысл вашего последнего примера в вашем ответе. Вы имеете в виду, что действия с изменчивыми варами никогда не должны содержать гонку данных, но согласно текущему определению гонки данных, действия с изменчивыми варами по-прежнему содержат гонку данных. Я правильно понимаю? Большое спасибо. - person newman; 23.08.2012
comment
Смысл в том, что определение в спецификации должно быть зафиксировано таким образом. Это то, что обсуждалось в списке рассылки модели памяти еще в 2005 году. - person Marko Topolnik; 23.08.2012
comment
@MarkoTopolnik, я только что прочитал исходное письмо Барта. Я могу понять каждое его предложение, но я до сих пор не могу понять, почему он сказал, что если действия с изменчивыми варами содержат гонку данных, то гарантия, о которой он сказал, не может быть применена. Не могли бы вы объяснить это более подробно в своем ответе или здесь? Большое спасибо. - person newman; 23.08.2012
comment
Дело в том, что действия с изменчивыми переменными, по самой природе изменчивой, никогда не участвуют в гонке данных. Определение должно это отражать. - person Marko Topolnik; 23.08.2012
comment
@MarkoTopolnik, спасибо за ответ. Но я до сих пор не могу понять, почему он сказал, что если действия с volatile vars содержат гонку данных, то гарантия (... если и только если ... в JLS), о которой он упоминал, не может быть применена. Не могли бы вы ответить на этот вопрос поподробнее? - person newman; 23.08.2012
comment
Боюсь, мне становится все труднее сделать это еще яснее и яснее. Программа, которая разделяет только изменчивые переменные между потоками, не может содержать гонку данных, вопреки определению гонки данных в JLS. - person Marko Topolnik; 23.08.2012