C ++ читает и записывает int Atomic? - PullRequest
77 голосов
/ 10 сентября 2008

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

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

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

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

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

Ответы [ 15 ]

64 голосов
/ 10 сентября 2008

Мальчик, что за вопрос. Ответ на который:

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

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

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

44 голосов
/ 10 сентября 2008

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

11 голосов
/ 10 сентября 2008

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

8 голосов
/ 10 сентября 2008

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

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

3 голосов
/ 17 сентября 2008

В Windows Interlocked *** Exchange *** Add гарантированно будет атомарным.

3 голосов
/ 10 сентября 2008

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

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

В ядре Linux уже есть часть этого кода.

1 голос
/ 22 октября 2013

Определенно НЕТ! Этот ответ от нашего высшего авторитета C ++, М. Boost:
Операции над «обычными» переменными не гарантируются как атомарные.

1 голос
/ 11 сентября 2008

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

0 голосов
/ 28 марта 2012

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

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

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

0 голосов
/ 19 августа 2010

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

...