Когда следует использовать функцию Win32 InterlockedExchange?

Я столкнулся с функцией InterlockedExchange и задавался вопросом, когда я должен использовать эту функцию. На мой взгляд, установка 32-битного значения на процессоре x86 всегда должна быть атомарной?
В случае, когда я хочу использовать функцию, новое значение не зависит от старого значения (это не операция увеличения). Не могли бы вы привести пример, где этот метод является обязательным (я не ищу InterlockedCompareExchange)

Ответ 1

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

Механизмы синхронизации потоков обеспечивают синхронизацию между ядрами, для получения дополнительной информации смотрите http://blogs.msdn.com/oldnewthing/archive/2008/10/03/8969397.aspx или google для получения и выпуска семантики

Ответ 2

Также, как и запись нового значения, InterlockedExchange также считывает и возвращает предыдущее значение; вся эта операция является атомной. Это полезно для алгоритмов блокировки.

(Кстати, 32-разрядные записи не гарантируются как атомарные. Рассмотрим случай, когда запись не выравнивается и, например, перекрывает границу кэша.)

Ответ 3

InterlockedExchange - это как запись, так и чтение - она ​​возвращает предыдущее значение.

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

Ответ 4

Установка 32-битного значения является атомарным, но только если вы устанавливаете литерал.

b = a - 2 операции:

mov         eax,dword ptr [a] 
mov         dword ptr [b],eax 

Теоретически может быть некоторое прерывание между первой и второй операциями.

Ответ 5

Написание значения никогда не является атомарным по умолчанию. Когда вы записываете значение в переменную, генерируются несколько машинных команд. С современными, превентивными операционными системами ОС может переключиться на другой поток между отдельными операциями записи.

Это еще больше проблема на многопроцессорных машинах, где одновременно может выполняться несколько потоков, и одновременно пытается записать в одно место памяти.

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

Ответ 6

InterlockedExchange гарантирует, что изменение переменной и возврат ее исходного значения не прерываются другими потоками.

Итак, если "i" является int, эти вызовы (взятые индивидуально) не нуждаются в InterlockedExchange вокруг "i":

a = i;
i = 9;
i = a;
i = a + 9;
a = i + 9;
if(0 == i)

Ни одно из этих утверждений не должно основываться на начальных И конечных значениях "i". Но эти следующие вызовы DO требуют InterlockedExchange вокруг 'i':

a = i++;  //a = InterlockedExchange(&i, i + 1);

Без него два потока, проходящих через этот же код, могут получить одно и то же значение "i", назначенное "a" или "a", могут неожиданно пропускать два или более числа.

if(0 == i++) //if(0 == InterlockedExchange(&i, i + 1))

Два потока могут одновременно выполнять код, который должен только однажды произойти.
и др.

Ответ 7

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

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

  • 32-битное чтение и запись ARE atomic, но в зависимости от вашего кода это может не означать много.
  • не беспокойтесь о не выровненных чтениях/записи. ВСЕ 32-разрядные записи в 32-битную переменную должны быть выровнены или ошибки страницы машины.
  • не волнуйтесь о переносе записи в конец кешированной страницы, что не может произойти.
  • Если вам нужно писать, а затем читать в одном потоке, и вы пишете в другом потоке, то вам нужно использовать InterlockedExchange. Если вы просто читаете значение в одном потоке и пишете его на другом, то вам не нужно его использовать, но эти значения могут быть wiggly из-за многопоточности.