, , - , , .
. char -can-alias - , , , , (, gcc, clang MSVC) (, x86).
, . ISO ++ 11 " " , char[] ( , c[0] c[1] ). , |= char , atomic<char>, , , , |=.
, UB , , , () , . (, , , .. atomic<int> -punning atomic<char> . , "" , type-punning atomic , atomic<int/char> , , .
, -punning ISO ++. , char*, char. union-punning ISO C99 GNU GNU C89 GNU ++, ++.
, , ? , ..
character |= 1 ( ) asm, char, , . x86 destination-destination or, ( , ). - RMW, .
--, , , - -- . asm, , . ( , . std::atomic, , ...)
:
thread A | thread B
-------------------|--------------
read tmp=c=0000 |
|
| c|=0b1100
tmp |= 1 # tmp=1 |
store c = tmp
c= 1, 1101, . / , B.
asm, , ( Godbolt):
void t1(U &v, unsigned mask) {
char old_value = v.atomic.load(std::memory_order_relaxed);
while (!v.atomic.compare_exchange_weak(old_value, old_value | mask)) {}
}
t1(U&, unsigned int):
movzx eax, BYTE PTR [rdi] # atomic load of the old value
.L2:
mov edx, eax
or edx, esi # esi = mask (register arg)
lock cmpxchg BYTE PTR [rdi], dl # atomic CAS, uses AL implicitly as the expected value, same semantics as C++11 comp_exg seq_cst
jne .L2
ret
void t2(U &v) {
v.character |= 0b1;
}
t2(U&):
or BYTE PTR [rdi], 1 # NON-ATOMIC RMW of the whole byte.
ret
, v.character |= 1 , v.atomic ^= 0b1100000 ( CAS) .
, , XOR, , . , or XOR. , , 0x10 - , 50% , 1 16 , 4 .
, , .
, ?
, , . , , , CPU - , . .
, , , (MESI), . L1D, . . num ++ 'int num'? .