InterlockedExchange и видимость памяти - PullRequest
8 голосов
/ 07 октября 2011

Я прочитал статью Проблемы с синхронизацией и многопроцессорностью , и у меня есть вопрос о InterlockedCompareExchange и InterlockedExchange. Вопрос на самом деле о последнем примере в статье. У них есть две переменные iValue и fValueHasBeenComputed, а в CacheComputedValue() они изменяют каждую из них, используя InterlockedExchange:

InterlockedExchange ((LONG*)&iValue, (LONG)ComputeValue());  // don't understand
InterlockedExchange ((LONG*)&fValueHasBeenComputed, TRUE); // understand

Я понимаю, что могу использовать InterlockedExchange для модификации iValue, но достаточно ли это просто, чтобы сделать

iValue = ComputeValue();

Так действительно ли необходимо использовать InterlockedExchange для установки iValue? Или другие потоки будут правильно видеть iValue, даже если iValue = ComputeValue();. Я имею в виду, что другие потоки будут правильно видеть iValue, потому что после него стоит InterlockedExchange.

Существует также статья Принципиальная модель последовательной памяти для платформ собственного кода Microsoft . Есть пример 3.1.1 с более или менее одинаковым кодом. Одна из рекомендаций Make y interlocked. Обратите внимание - не оба y и x.

Обновление
Просто чтобы уточнить вопрос. Проблема в том, что я вижу противоречие. Пример из «Проблемы синхронизации и многопроцессорности» использует два InterlockedExchange. Напротив, в примере 3.1.1 «Базовый перезапись» (который, я думаю, очень похож на первый пример) Херб Саттер дает эту рекомендацию

"Сделать y заблокированным: если y заблокирован, то на y нет гонки потому что это атомно обновляемый, и нет никакой гонки на х, потому что -> b -> d. "

. В этом проекте Херб не использует две взаимосвязанные переменные (если я прав, он подразумевает использование InterlockedExchange только для y).

Ответы [ 4 ]

1 голос
/ 07 октября 2011

Они сделали это для предотвращения частичного чтения / записи, если адрес iValue не выровнен с адресом, который гарантирует атомарный доступ. эта проблема возникает, когда два или более физических потока пытаются записать значение одновременно, или один читает, а другой пытается писать одновременно.

В качестве вторичной точки следует отметить, что магазины не всегда видны глобально, они будут видны только при сериализации, либо через забор, либо через шину.

0 голосов
/ 19 октября 2011

Я думаю, что это обсуждение имеет ответ на вопрос: Неявные барьеры памяти .

Вопрос : вызывает ли InterlockedExchange (неявный полный забор) на T1 и T2, уверен, что T2 "увидит" запись, выполненную T1 перед забором?(Переменные A, B и C), даже если эти переменные не находятся в той же строке кэша, что и Foo и Bar?

Ответ : Да - полный забор, генерируемыйInterlockedExchange гарантирует, что записи в A, B и C не будут переупорядочены за пределами ограничения, неявного в вызове InterlockedExchange.Это точка семантики барьера памяти.Они не обязательно должны находиться в одной строке кэша.

Барьеры памяти: аппаратное представление для хакеров программного обеспечения и Вопросы программирования без блокировки для Xbox 360 и Microsoft Windows также интересны.

0 голосов
/ 09 октября 2011

Существует два возможных разрешения противоречия, которое вы наблюдали.

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

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

0 голосов
/ 07 октября 2011

Вы просто получаете атомарную операцию с InterlockedExchange.Зачем тебе это надо?Причина InterlockedExchange делает 2 вещи.

  1. Заменяет значение переменной
  2. Возвращает старое значение

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

И вы также предотвращаете скачки данных для этого значения. здесь вы получите хорошее объяснение, почему чтение / запись на LONG не является атомарным

...