встроенные функции gcc atomic - PullRequest
21 голосов
/ 22 июля 2011

http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Atomic-Builtins.html

Я полагаю, что следующий код атомарно увеличивает значение var.

volatile int var = 0;
__sync_fetch_and_add( &var, 1 )

Я понял вышеуказанные коды как следующую логику :

  1. Загрузка адреса переменной var
  2. запись числа 1 в переменную var атомарно - через регистр / кэш, каким-то образом

Однако я сомневаюсь, чтоследующее тоже атомарное

volatile int var = 0;
volatile int num = 1;
__sync_fetch_and_add( &var, num )

Поскольку его можно интерпретировать как

  1. Загрузить адрес переменной var
  2. Загрузить значение переменной num в регистр
  3. записать значение в переменную var.

После выполнения # 2, но до # 3 ЦП / поток прерывается, а другой ЦП / поток обновляет значение переменной num.

Другими словами, при использовании _ sync * () gcc, могу ли я использовать переменную, а не константу, в качестве второго аргумента?

Разве неэто нарушает атомность?

1 Ответ

29 голосов
/ 22 июля 2011

Операция на самом деле является двумя операциями.

__sync_fetch_and_add( &var, num )

Загрузка num является атомарной.Добавление его к var является атомарным.Но две атомарные операции не делают атомарную операцию, когда объединены.Вот почему так сложно изобрести новые структуры данных без блокировки. Как правило, две поточно-ориентированные операции не обязательно делают поточно-ориентированную операцию при компоновке. По этой причине так сложно создавать правильные многопоточные приложения.

Видите ли,__sync_fetch_and_add действительно атомарный, но он ведет себя как обычная функция - поэтому он принимает текущее значение «num» в качестве параметра.Не совсем корректно говорить, что атомарность функции нарушена, потому что вызывающая сторона несет ответственность за загрузку значения из num и не является частью интерфейса функции.Я мог бы также жаловаться на это:

__sync_fetch_and_add(&var, some_really_long_function());

Или еще хуже,

__sync_fetch_and_add(long_function_1(), long_function_2());

Вы говорите это "может интерпретироваться как"

  1. Загрузить адреспеременная var
  2. Загрузить значение переменной num
  3. Выполнить атомарное сложение

Но в соответствии со спецификацией C это не значит, что может интерпретируется таким образом, но скорее должно интерпретироваться таким образом, иначе компилятор не будет совместимым (на самом деле он может поменять местами # 1 и # 2, но это не важно).

...