I got this example of spinlock from Anthony Williams, and its something wrong with it (or I had a long day).
#include <atomic>
class spinlock
{
std::atomic_flag flag;
public:
spinlock() : flag(ATOMIC_FLAG_INIT) {}
void lock() {
while (flag.test_and_set(std::memory_order_acquire));
}
void unlock(){
flag.clear(std::memory_order_release);
}
};
spinlock sl;
void f()
{
std::lock_guard lc(sl);
}
int main()
{
f();
}
So this is enough for std::lock_guard to acquire it, but I have a compilation error.
error C2280: 'std::atomic_flag::atomic_flag(const std::atomic_flag &)': attempting to reference a deleted function
To be honest I dont see how spinlock() : flag(ATOMIC_FLAG_INIT) {} is calling a copy constructor.
I use VS2022 with C 20 standard and ATOMIC_FLAG_INIT is defined as following:
#define ATOMIC_FLAG_INIT \
{}
Is this book example broken, or am I donning something wrong?
CodePudding user response:
ATOMIC_FLAG_INIT can only be used as follows:
std::atomic_flag v = ATOMIC_FLAG_INIT;
It is unspecified if
flag(ATOMIC_FLAG_INIT)
will work. If visual studio defines ATOMIC_FLAG_INIT as {} then your code is presumably ending up creating an std::atomic_flag with {} then calling the deleted copy constructor of flag.
If you're using c 20 you can simply remove the flag initialiser as std::atomic_flag's default constructor now initialises to false.
Without c 20 I think the only way to do this according to the standard is to use an inline initialiser:
class spinlock
{
std::atomic_flag flag = ATOMIC_FLAG_INIT;
public:
void lock() {
while (flag.test_and_set(std::memory_order_acquire));
}
void unlock(){
flag.clear(std::memory_order_release);
}
};
