Короче говоря, это очень зависит от процессора и компилятора.
Скажем, у вас есть 32-битное значение, содержащее ноль, и поток A хочет установить бит 0, а поток B хочет установить бит 1.
Как вы описываете, это операции чтения-изменения-записи, и проблема синхронизации заключается в том, «что произойдет, если они сталкиваются».
Случай, который вам нужно избегать, таков:
A: Reads (gets 0)
B: Reads (also gets zero)
A: Logical-OR bit 0, result = 1
A: Writes 1
B: Logical-OR bit 1, result = 2
B: Writes 2 - oops, should have been 3
... когда правильный результат будет таким ...
A: Reads (gets 0)
A: Logical-OR bit 0, result = 1
A: Writes 1
B: Reads (gets 1)
B: Logical-OR bit 1, result = 2
B: Writes 3 - correct
На некоторых процессорах запись с изменением для чтения будет представлять собой три отдельные инструкции, поэтому вам потребуется синхронизация.На других это будет единственная атомарная инструкция.В системах с несколькими ядрами / процессорами это будет одна инструкция, но другие ядра / процессоры могут иметь к ней доступ, поэтому вам снова потребуется синхронизация.
Выполнение этого с байтами может быть таким же.В некоторых архитектурах памяти процессора вы можете записать только 32-битное значение памяти, поэтому для байтовых обновлений требуется чтение-изменение-запись, как и раньше.
Обновление для архитектуры X86 (и особенно для Windows)
Windows предоставляет набор элементарных «блокированных» операций над 32-разрядными значениями, включая Логическое ИЛИ .Это может помочь вам избежать критических разделов.но будьте осторожны, потому что, как указывает Раймонд Чен, они не решают все .Продолжайте читать этот пост, пока не поймете его!