Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

atomic double-width problem...

36 views
Skip to first unread message

Chris M. Thomasson

unread,
Mar 20, 2018, 4:24:43 AM3/20/18
to
I have always used my custom asm for this, but I noticed a while ago
that C++11 can use Double-Width Compare-and-Swap (DWCAS) via a struct
the size of two pointers for atomic operations. Out of interest, I have
constructed the following program that works on MSVC 14.0.25424.00
Update 3. However, on GCC 6.3.0, I am getting the following errors:
____________________________
||=== Build: Debug in ct_experiment (compiler: GNU GCC Compiler) ===|
obj\Debug\main.o||In function `std::atomic<ct_dwcas>::is_lock_free()
const':|
C:\msys64\mingw64\include\c++\6.3.0\atomic|212|undefined reference to
`__atomic_is_lock_free'|
obj\Debug\main.o||In function
`std::atomic<ct_dwcas>::load(std::memory_order) const':|
C:\msys64\mingw64\include\c++\6.3.0\atomic|235|undefined reference to
`__atomic_load_16'|
obj\Debug\main.o||In function
`std::atomic<ct_dwcas>::compare_exchange_weak(ct_dwcas&, ct_dwcas,
std::memory_order, std::memory_order)':|
C:\msys64\mingw64\include\c++\6.3.0\atomic|268|undefined reference to
`__atomic_compare_exchange_16'|
||error: ld returned 1 exit status|
||=== Build failed: 4 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
____________________________

Here is the code:
____________________________
#if defined (_MSC_VER)
# define _ENABLE_ATOMIC_ALIGNMENT_FIX // for dwcas
#endif

#include <iostream>
#include <cstdlib>
#include <cstdint>



#include <atomic>

#define ct_mb_relaxed std::memory_order_relaxed
#define ct_mb_acquire std::memory_order_acquire
#define ct_mb_fence(mb_membar) std::atomic_thread_fence((mb_membar))


struct ct_dwcas
{
std::uintptr_t a;
std::uintptr_t b;
};

typedef std::atomic<ct_dwcas> ct_dwcas_atomic;



int main()
{
{
ct_dwcas_atomic dwcas = { ct_dwcas { 1, 2 } };


bool status = dwcas.is_lock_free();

std::cout << "dwcas.is_lock_free():" << status << "\n";

if (! status)
{
std::cout << "\n\nOuch! You are $#%! out of luck. No DWCAS
for you!\n";
return EXIT_FAILURE;
}


std::cout << dwcas.load(ct_mb_relaxed).a << "\n";
std::cout << dwcas.load(ct_mb_relaxed).b << "\n";

ct_dwcas load = dwcas.load(ct_mb_relaxed);

for (;;)
{
ct_dwcas store = { load.a + 2, load.b + 4 };

if (dwcas.compare_exchange_weak(load, store, ct_mb_relaxed))
{
break;
}
}

std::cout << dwcas.load(ct_mb_relaxed).a << "\n";
std::cout << dwcas.load(ct_mb_relaxed).b << "\n";

for (;;)
{
ct_dwcas store = { load.a + 2, load.b + 4 };

if (dwcas.compare_exchange_weak(load, store, ct_mb_relaxed))
{
break;
}
}

std::cout << dwcas.load(ct_mb_relaxed).a << "\n";
std::cout << dwcas.load(ct_mb_relaxed).b << "\n";
}

std::cout << "\n\nFin!\n";
std::cout.flush();
std::cin.get();

return EXIT_SUCCESS;
}
____________________________

The output should be:
____________________________
dwcas.is_lock_free():1
1
2
3
6
5
10


Fin!
____________________________



I must be missing something in the ct_dwcas struct. Humm...

Any thoughts? Help? Thanks. :^)

Alf P. Steinbach

unread,
Mar 20, 2018, 4:28:26 AM3/20/18
to
On 20.03.2018 09:24, Chris M. Thomasson wrote:
> I have always used my custom asm for this, but I noticed a while ago
> that C++11 can use Double-Width Compare-and-Swap (DWCAS) via a struct
> the size of two pointers for atomic operations. Out of interest, I have
> constructed the following program that works on MSVC 14.0.25424.00
> Update 3. However, on GCC 6.3.0, I am getting the following errors:
> ____________________________
> ||=== Build: Debug in ct_experiment (compiler: GNU GCC Compiler) ===|
> obj\Debug\main.o||In function `std::atomic<ct_dwcas>::is_lock_free()
> const':|
> C:\msys64\mingw64\include\c++\6.3.0\atomic|212|undefined reference to
> `__atomic_is_lock_free'|
> obj\Debug\main.o||In function
> `std::atomic<ct_dwcas>::load(std::memory_order) const':|
> C:\msys64\mingw64\include\c++\6.3.0\atomic|235|undefined reference to
> `__atomic_load_16'|
> obj\Debug\main.o||In function
> `std::atomic<ct_dwcas>::compare_exchange_weak(ct_dwcas&, ct_dwcas,
> std::memory_order, std::memory_order)':|
> C:\msys64\mingw64\include\c++\6.3.0\atomic|268|undefined reference to
> `__atomic_compare_exchange_16'|
> ||error: ld returned 1 exit status|
> ||=== Build failed: 4 error(s), 0 warning(s) (0 minute(s), 0 second(s))
> ===|
>

[snip]
>
> I must be missing something in the ct_dwcas struct. Humm...
>
> Any thoughts? Help?  Thanks. :^)

You probably need to link with some support library.

Until g++ 8.0 it was that way for e.g. filesystem sub-library.

Maybe it's still that way, IDK, I'm still on 7.2.


Cheers!,

- Alf

Chris M. Thomasson

unread,
Mar 20, 2018, 4:55:18 AM3/20/18
to
Humm... Thank you. Well, I am building in 64-bit mode. So, that must be
it: there are no 128-bit atomics in them there hills! I notice
__atomic_load_16, well that is for two 64-bit pointers. Damn it!

Okay, I will try a build in 32-bit mode and that should give me
__atomic_load_8, which should correspond to to the size of two adjacent
32-bit pointers in the ct_dwcas struct: Everything should just work.
Will have some more time tomorrow. Thanks again Alf.

Chris M. Thomasson

unread,
Mar 20, 2018, 5:05:28 AM3/20/18
to
Fwiw, simply changing ct_dwcas to:

struct ct_dwcas
{
std::uint32_t a;
std::uint32_t b;
};

on a 64-bit build works like a charm. So:

struct ct_dwcas
{
std::uintptr_t a;
std::uintptr_t b;
};

will work like a charm in 32-bit mode. Got it.

Marcel Mueller

unread,
Mar 21, 2018, 2:37:29 PM3/21/18
to
On 20.03.18 09.55, Chris M. Thomasson wrote:
> Humm... Thank you. Well, I am building in 64-bit mode. So, that must be
> it: there are no 128-bit atomics in them there hills!

But that is a compiler restriction. x86-64 has the native CMPXCHG16B
instruction which swaps 128 bit atomically.


Marcel

Chris M. Thomasson

unread,
Mar 21, 2018, 7:13:27 PM3/21/18
to
It does, I remember a while ago when the support of CMPXCHG16B was
sketchy. Afaict, this is a valid reason to keep my assembly language
code around, C++11 aside for a moment.

Btw, I also remember the weird Itanium CMP8XCHG16 instruction. 64-bit
version count with 128-bit pointer? Must be for linked data-structures.
0 new messages