Когда следует использовать функцию Win32 InterlockedExchange? - PullRequest
19 голосов
/ 16 октября 2008

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

Ответы [ 7 ]

11 голосов
/ 16 октября 2008

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

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

10 голосов
/ 16 октября 2008

InterlockedExchange является записью и чтением - возвращает предыдущее значение.

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

4 голосов
/ 16 октября 2008

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

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

3 голосов
/ 16 октября 2008

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

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

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

3 голосов
/ 16 октября 2008

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

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

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

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

2 голосов
/ 13 мая 2011

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

Итак, если 'i' является целым числом, эти вызовы (взятые по отдельности) не требуют InterlockedExchange вокруг 'i':

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

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

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

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

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

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

0 голосов
/ 12 февраля 2014

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

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

  1. 32-битное чтение и запись являются атомарными, но в зависимости от вашего кода это может не иметь большого значения.
  2. не беспокойтесь о внеблоковом чтении / записи. ВСЕ 32-битные записи в 32-битную переменную должны быть выровнены или ошибки страницы компьютера.
  3. не беспокойтесь о переносе записи вокруг конца кэшированной страницы, этого не может быть.
  4. Если вам нужно писать-потом-читать в одном потоке, а вы пишете в другом потоке, вам необходимо использовать InterlockedExchange. Если вы просто читаете значение в одном потоке и записываете его в другом, вам не нужно его использовать, но эти значения могут быть неоднозначными из-за многопоточности.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...