Неверно, что программа может быть правильно синхронизирована и иметь гонку данных. Пример от 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