C++ Synchronized and Atomic Software Transactional Memory

376 views Asked by At

I read the cppreference guide over the sperimental feature of transactional memory and i try it.

I write some simple code with sincronized that as say cpp reference is not a transaction but only guarantees that the operation in the block are executed in a total order, the i write the same code with atomic_noexcept and atomic_commit, not with atomic_cancel that seems to be not yet implemented.

The doubt that i have is about the difference between atomic_noexcept, atomic_commit and synchronized, apparently they work in the same way, except for the compilation error if a no transaction safe function is called in an atomic block.

So I analyze the assembly code for the 3 variants, and result the same, as reported below:

cpp atomic_noexcept:

int a;

void thread_func() {
    
    atomic_noexcept
    {
      ++a;          
    }       
}

assembly 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;          
    }       
}

assembly 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 synchronized:

int a;

void thread_func() {
    
    synchronized
    {
      ++a;          
    }       
}

assembly synchronized:

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

How can they work differently? For example i report the explanation of different atomic block of cppreference:

atomic_noexcept : If an exception is thrown, std::abort is called

atomic_cancel : If an exception is thrown, std::abort is called, unless the exception is one of the exceptions uses for transaction cancellation (see below) in which case the transaction is cancelled: the values of all memory locations in the program that were modified by side effects of the operations of the atomic block are restored to the values they had at the time the start of the atomic block was executed, and the exception continues stack unwinding as usual.

atomic_commit : If an exception is thrown, the transaction is committed normally.

How can atomic_noexcept work differently from atomic_commit if has the same assembly code? How can syncronized block work differently from atomic block if has the same assembly code?

EDIT:

All these test and assembly code are extracted from last version of GCC (V. 10.2)

EDIT2:

After some test and research i haven't found yet a logical explanation for the said different behaviour.

0

There are 0 answers