Подтвердить что ты не робот

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

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

4b9b3361

Ответ 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 из-за многопоточности.