Как атомарно выполнить последовательную загрузку и сохранить операции?
Рассмотрим этот код в GCC 4.8.0:
std::atomic<bool> a;
std::atomic<bool> b;
a.store( b.load() ); // want to be atomic
Как я могу сделать строку выше, чтобы быть атомарной в целом? Другими словами, как получить атомное присвоение атомных переменных?
Есть ли альтернативы std::atomic
которые позволяют это?
я нашел __transaction_atomic {/* any code goes here */}
который активируется в GCC -fgnu-tm
, При этом в блоке можно написать что угодно, и это будет выполнено атомарно.
Теперь вопрос:
Является __transaction_atomic
реализовано с мьютексами? Если да, то какой мьютекс на самом деле блокирует?
Есть ли реализация __transaction_atomic
изменить в зависимости от того, что находится в его блоке? Если да, то как это меняется?
2 ответа
Теоретически подстановка атомарных переменных может быть реализована на нескольких процессорах с поддержкой DCAS. На практике ни один современный процессор не имеет поддержки DCAS, поэтому это невозможно.
Я не думаю, что это возможно. Я не думаю, что полезно иметь такую операцию. Зачем тебе это? Если у вас есть такие жесткие требования, то вы должны просто использовать std::mutex
заперт a = b
назначение.
ОБНОВИТЬ
Я проверил __transaction_atomic
блок с GCC 4.8.1 Cygwin64 и этот очень короткий источник
extern int a, b;
void foo ()
{
__transaction_atomic
{
a = b;
}
}
приводит к множеству команд, вызывающих функции библиотеки ITM
_Z3foov:
.LFB0:
pushq %rdi #
.seh_pushreg %rdi
pushq %rsi #
.seh_pushreg %rsi
subq $200, %rsp #,
.seh_stackalloc 200
movaps %xmm6, 32(%rsp) #,
.seh_savexmm %xmm6, 32
movaps %xmm7, 48(%rsp) #,
.seh_savexmm %xmm7, 48
movaps %xmm8, 64(%rsp) #,
.seh_savexmm %xmm8, 64
movaps %xmm9, 80(%rsp) #,
.seh_savexmm %xmm9, 80
movaps %xmm10, 96(%rsp) #,
.seh_savexmm %xmm10, 96
movaps %xmm11, 112(%rsp) #,
.seh_savexmm %xmm11, 112
movaps %xmm12, 128(%rsp) #,
.seh_savexmm %xmm12, 128
movaps %xmm13, 144(%rsp) #,
.seh_savexmm %xmm13, 144
movaps %xmm14, 160(%rsp) #,
.seh_savexmm %xmm14, 160
movaps %xmm15, 176(%rsp) #,
.seh_savexmm %xmm15, 176
.seh_endprologue
movl $43, %edi #,
xorl %eax, %eax #
call _ITM_beginTransaction #
testb $2, %al #, tm_state.4
je .L2 #,
movq .refptr.b(%rip), %rax #, tmp67
movl (%rax), %edx # b, b
movq .refptr.a(%rip), %rax #, tmp66
movl %edx, (%rax) # b, a
movaps 32(%rsp), %xmm6 #,
movaps 48(%rsp), %xmm7 #,
movaps 64(%rsp), %xmm8 #,
movaps 80(%rsp), %xmm9 #,
movaps 96(%rsp), %xmm10 #,
movaps 112(%rsp), %xmm11 #,
movaps 128(%rsp), %xmm12 #,
movaps 144(%rsp), %xmm13 #,
movaps 160(%rsp), %xmm14 #,
movaps 176(%rsp), %xmm15 #,
addq $200, %rsp #,
popq %rsi #
popq %rdi #
jmp _ITM_commitTransaction #
.p2align 4,,10
.L2:
movq .refptr.b(%rip), %rcx #,
call _ITM_RU4 #
movq .refptr.a(%rip), %rcx #,
movl %eax, %edx # D.2368,
call _ITM_WU4 #
call _ITM_commitTransaction #
nop
movaps 32(%rsp), %xmm6 #,
movaps 48(%rsp), %xmm7 #,
movaps 64(%rsp), %xmm8 #,
movaps 80(%rsp), %xmm9 #,
movaps 96(%rsp), %xmm10 #,
movaps 112(%rsp), %xmm11 #,
movaps 128(%rsp), %xmm12 #,
movaps 144(%rsp), %xmm13 #,
movaps 160(%rsp), %xmm14 #,
movaps 176(%rsp), %xmm15 #,
addq $200, %rsp #,
popq %rsi #
popq %rdi #
ret
.seh_endproc
.ident "GCC: (GNU) 4.8.1"
.def _ITM_beginTransaction; .scl 2; .type 32; .endef
.def _ITM_commitTransaction; .scl 2; .type 32; .endef
.def _ITM_RU4; .scl 2; .type 32; .endef
.def _ITM_WU4; .scl 2; .type 32; .endef
.section .rdata$.refptr.b, "dr"
.globl .refptr.b
.linkonce discard
.refptr.b:
.quad b
.section .rdata$.refptr.a, "dr"
.globl .refptr.a
.linkonce discard
.refptr.a:
.quad a
Это было с -O3
вариант.