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?
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);
}
};