我阅读了关于事务内存的实验特性的cppreference指南,并尝试了它。
我写了一些简单的代码sincronized
,说 cpp 引用不是事务,但只保证块中的操作按总顺序执行,我用 and 编写相同的代码,atomic_noexcept
而atomic_commit
不是atomic_cancel
似乎尚未实现。
我的疑问是关于和之间的区别atomic_noexcept
,显然它们以相同的方式工作,除了在原子块中调用无事务安全函数时会出现编译错误。atomic_commit
synchronized
因此,我分析了 3 个变体的汇编代码,结果相同,如下所示:
cpp atomic_noexcept:
int a;
void thread_func() {
atomic_noexcept
{
++a;
}
}
程序集 atomic_noexcept:
thread_func():
subq $8, %rsp
movl $43, %edi
xorl %eax, %eax
call _ITM_beginTransaction
testb $2, %al
jne .L2
movl $a, %edi
call _ITM_RfWU4
movl $a, %edi
leal 1(%rax), %esi
call _ITM_WaWU4
call _ITM_commitTransaction
addq $8, %rsp
ret
.L2:
addl $1, a(%rip)
addq $8, %rsp
jmp _ITM_commitTransaction
a:
.zero 4
cpp atomic_commit:
int a;
void thread_func() {
atomic_commit
{
++a;
}
}
程序集 atomic_commit:
thread_func():
subq $8, %rsp
movl $43, %edi
xorl %eax, %eax
call _ITM_beginTransaction
testb $2, %al
jne .L2
movl $a, %edi
call _ITM_RfWU4
movl $a, %edi
leal 1(%rax), %esi
call _ITM_WaWU4
call _ITM_commitTransaction
addq $8, %rsp
ret
.L2:
addl $1, a(%rip)
addq $8, %rsp
jmp _ITM_commitTransaction
a:
.zero 4
cpp 同步:
int a;
void thread_func() {
synchronized
{
++a;
}
}
组装同步:
thread_func():
subq $8, %rsp
movl $43, %edi
xorl %eax, %eax
call _ITM_beginTransaction
testb $2, %al
jne .L2
movl $a, %edi
call _ITM_RfWU4
movl $a, %edi
leal 1(%rax), %esi
call _ITM_WaWU4
call _ITM_commitTransaction
addq $8, %rsp
ret
.L2:
addl $1, a(%rip)
addq $8, %rsp
jmp _ITM_commitTransaction
a:
.zero 4
他们如何以不同的方式工作?例如,我报告了 cppreference 的不同原子块的解释:
atomic_noexcept :如果抛出异常,则调用 std::abort
atomic_cancel:如果抛出异常,则调用 std::abort ,除非异常是用于事务取消的异常之一(见下文),在这种情况下事务被取消:程序中所有内存位置的值被原子块操作的副作用修改的值恢复到它们在原子块开始执行时的值,并且异常继续像往常一样展开堆栈。
atomic_commit:如果抛出异常,则事务正常提交。
如果具有相同的汇编代码,atomic_noexcept
工作方式有何不同?atomic_commit
如果具有相同的汇编代码,同步块与原子块的工作方式有何不同?
编辑:
所有这些测试和汇编代码都是从最新版本的 GCC (V. 10.2) 中提取的
编辑2:
经过一些测试和研究,我还没有找到对上述不同行为的合乎逻辑的解释。