2008-09-10 2 views
69

У меня есть два потока, один из которых обновляет int и один читает его. Это статистическое значение, в котором порядок чтения и записи не имеет значения.Чтение и запись C++ для int Atomic?

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

Например, подумайте о значении = 0x0000FFFF, которое получает добавочное значение 0x00010000.

Есть ли время, когда значение выглядит как 0x0001FFFF, о котором я должен беспокоиться? Конечно, чем больше тип, тем более вероятно что-то подобное.

Я всегда синхронизировал эти типы доступа, но было любопытно, что думает сообщество.

+4

Действительно? Мне было бы безразлично, что думает сообщество. Мне все равно, что факты :) – sehe 2011-09-28 18:22:11

+1

Интересное чтение по теме: http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1- of-2 – ereOn 2013-07-03 09:01:41

+0

В частности, для `=`: http://stackoverflow.com/questions/8290768/is-assignment-operator-atomic – 2015-06-16 10:53:16

ответ

39

Сначала можно подумать, что чтение и запись собственного размера машины являются атомарными, но есть ряд проблем, связанных с когерентностью кеш-памяти между процессорами/ядрами. Используйте атомные операции, такие как Interlocked * в Windows и эквивалент в Linux. C++ 0x будет иметь «атомный» шаблон, чтобы обернуть их в приятный и кросс-платформенный интерфейс. На данный момент, если вы используете уровень абстракции платформы, это может обеспечить эти функции. ACE., Смотрите шаблон шаблона ACE_Atomic_Op.

+0

Документ ACE_Atomic_Op перемещен - его можно найти по адресу http://www.dre.vanderbilt.edu/~schmidt/DOC_ROOT/ACE/ace/Atomic_Op.inl – Byron 2011-12-09 16:41:47

0

Нет, они не являются (или, по крайней мере, вы не можете предположить, что они есть). Сказав это, есть некоторые трюки, чтобы сделать это атомарно, но они обычно не переносимы (см. Compare-and-swap).

8

Да, вам нужно синхронизировать доступ. В C++ 0x это будет гонка данных и неопределенное поведение. С потоками POSIX это уже неопределенное поведение.

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

3

Необходимо синхронизировать, но на некоторых архитектурах есть эффективные способы сделать это.

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

Ядро Linux уже имеет часть этого кода.

9

ЕСЛИ вы читаете/записываете 4-байтовое значение И оно выровнено по DWORD в памяти И вы работаете на архитектуре I32, тогда чтение и запись являются атомарными.

+2

Где указано в руководствах разработчика программного обеспечения для архитектуры Intel? – 2011-01-03 16:56:16

+1

@ DanielTrebbien: возможно, см. Http: // stackoverflow.com/questions/5002046/atomicity-in-c-myth-or-reality – sehe 2011-09-28 18:23:39

57

Boy, какой вопрос. Ответ на который:

Да, нет, ммм, ну, это зависит

Это все сводится к архитектуре системы. На IA32 правильно выровненный адрес будет представлять собой атомную операцию. Невыраженные записи могут быть атомарными, это зависит от используемой системы кеширования. Если память лежит в одной строке кэша L1, то она является атомарной, иначе это не так. Ширина шины между процессором и ОЗУ может влиять на атомную природу: правильно выровненная 16-битная запись на 8086 была атомарной, тогда как одна и та же запись на 8088 была не потому, что 8088 имела только 8-битную шину, тогда как 8086 16-битная шина.

Кроме того, если вы используете C/C++, не забудьте пометить общее значение как изменчивое, в противном случае оптимизатор будет считать, что переменная никогда не обновляется ни в одном из ваших потоков.

+14

Ключевое слово volatile не полезно в многопоточных программах http://stackoverflow.com/questions/2484980/why-is-volatile-not-considered-useful -in-multithreaded-c-or-c-programming – 2012-07-05 12:13:38

+3

@IngeHenriksen: Я не убежден в этой ссылке. – Skizz 2012-07-05 13:12:27

0

Я согласен со многими и особенно с Jason. В окнах можно использовать InterlockedAdd и его друзей.

1

Чтобы предупредить, что все говорят наверху, язык pre-C++ 0x не может гарантировать что-либо доступ к общей памяти из нескольких потоков. Любые гарантии будут до компилятора.

0

Asside от выпуска кэша упомянутого выше ...

Если порт кода на процессор с меньшим размером регистра не будет атомными больше.

IMO, проблемы с резьбой слишком сложны, чтобы рисковать.

3

В Windows, с блокировкой *** Обмен *** Добавить гарантированно будет атомарным.

-1

Единственный переносимый способ - использовать тип sig_atomic_t, определенный в заголовке signal.h для вашего компилятора. В большинстве реализаций C и C++ это int. Затем объявите переменную как «volatile sig_atomic_t».

0

Давайте этот пример

int x; 
x++; 
x=x+5; 

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

Другой например,

x=5; 

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

0

tc, Я думаю, что в тот момент, когда вы используете константу (например, 6), инструкция не будет завершена в течение одного машинного цикла. Попытайтесь увидеть набор команд x + = 6 по сравнению с x ++

0

Некоторые люди считают, что ++ c является атомарным, но имеет глаза на сборку, сгенерированную. Например, с «GCC -S»:

movl cpt.1586(%rip), %eax 
addl $1, %eax 
movl %eax, cpt.1586(%rip) 

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

Смежные вопросы