Чтение и запись C ++ int Atomic?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Обратите внимание на проблему кеша, упомянутую выше …

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

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

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

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

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

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

 x=5; 

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

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

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

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

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

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

  • C # версия синхронизированного ключевого слова java?
  • Синхронизированный блок Java против Collections.synchronizedMap
  • Как @synchronized блокировка / разблокировка в Objective-C?
  • Синхронный запрос в Node.js
  • Избегайте синхронизации (это) в Java?
  • Как сделать мой ArrayList streamобезопасным? Другой подход к проблеме в Java?
  • Синхронизировано ли унаследовано в Java?
  • Как синхронизировать базу данных SQLite на телефоне Android с базой данных MySQL на сервере?
  • Как использовать свойство CancellationToken?
  • В чем разница между синхронизацией на lockObject и использованием этого как блокировки?
  • Синхронизация IPC с общей памятью (без блокировки)
  • Давайте будем гением компьютера.