Итак, я читал о модели памяти, которая является частью предстоящего стандарта С++ 0x. Тем не менее, я немного смущен некоторыми ограничениями для того, что разрешено компилятором, в частности, о спекулятивных нагрузках и хранилищах.
Для начала, некоторые из соответствующих материалов:
Страницы Hans Boehm о потоках и модели памяти в С++ 0x
Boehm, "Нити не могут быть реализованы как библиотека"
Boehm и Adve, "Основы модели памяти С++ Concurrency"
Boehm, "Concurrency последствия компилятора модели памяти" , N2338
Теперь основная идея - это, по сути, "Последовательная последовательность для программ без данных", которая, по-видимому, является достойным компромиссом между простотой программирования и возможностью оптимизации возможностей компилятора и оборудования. Готовность данных определяется так, что если два доступа к одному и тому же местоположению памяти разными потоками не упорядочены, по меньшей мере один из них хранится в ячейке памяти, и по меньшей мере одно из них не является действием синхронизации. Это подразумевает, что все права на чтение и запись для общих данных должны быть связаны с некоторым механизмом синхронизации, таким как мьютексы или операции над атомными переменными (ну, возможно, для атомных переменных можно использовать упорядоченное упорядочение памяти для экспертов, но по умолчанию предоставляется для последовательной согласованности).
В свете этого я смущен об ограничениях на ложные или спекулятивные нагрузки/хранилища на обычные общие переменные. Например, в N2338 мы имеем пример
switch (y) {
case 0: x = 17; w = 1; break;
case 1: x = 17; w = 3; break;
case 2: w = 9; break;
case 3: x = 17; w = 1; break;
case 4: x = 17; w = 3; break;
case 5: x = 17; w = 9; break;
default: x = 17; w = 42; break;
}
которому компилятору не разрешено преобразовывать в
tmp = x; x = 17;
switch (y) {
case 0: w = 1; break;
case 1: w = 3; break;
case 2: x = tmp; w = 9; break;
case 3: w = 1; break;
case 4: w = 3; break;
case 5: w = 9; break;
default: w = 42; break;
}
так как если y == 2 существует ложная запись в x, которая может быть проблемой, если другой поток одновременно обновляет x. Но почему это проблема? Это гонка данных, которая в любом случае запрещена; в этом случае компилятор просто делает это хуже, записывая x в два раза, но даже одной записи будет достаточно для гонки данных, нет? То есть правильной программе С++ 0x необходимо синхронизировать доступ к x, и в этом случае больше не будет расы данных, и ложный магазин тоже не будет проблемой?
Я также смущен о примере 3.1.3 в N2197 и некоторых других примерах, но, возможно, объяснение этой проблемы также объяснит это.
РЕДАКТИРОВАТЬ: Ответ:
Причина, по которой спекулятивные хранилища являются проблемой, заключается в том, что в приведенном выше примере оператора коммутатора программист, возможно, решил условно получить блокировку, защищающую x, только если y!= 2. Следовательно, спекулятивный магазин может ввести гонку данных, которая была не существует в исходном коде, и таким образом запрещается преобразование. Тот же аргумент применяется и к примеру 3.1.3 в N2197.