Reputation: 14416
In C++11
there is the std::atomic_flag
that is useful for thread loops:
static std::atomic_flag s_done(ATOMIC_FLAG_INIT);
void ThreadMain() {
while (s_done.test_and_set()) { // returns current value of s_done and sets to true
// do some stuff in a thread
}
}
// Later:
s_done.clear(); // Sets s_done to false so the thread loop will drop out
The ATOMIC_FLAG_INIT
sets the flag to false
which means that the thread never gets in the loop. A (bad) solution is possibly to do this:
void ThreadMain() {
// Sets the flag to true but erases a possible false
// which is bad as we may get into a deadlock
s_done.test_and_set();
while (s_done.test_and_set()) {
// do some stuff in a thread
}
}
The default constructor for std::atomic_flag
specifies that the flag will be in an unspecified state.
Can I initialize the atomic_flag
to true
? Is this the correct use of the atomic_flag
?
Upvotes: 2
Views: 1825
Reputation: 42554
You are incorrectly using atomic_flag
to implement a spinlock. The correct form would be:
static std::atomic_flag s_done(ATOMIC_FLAG_INIT);
void ThreadMain() {
while (s_done.test_and_set()) { // returns current value of s_done and sets to true
// spin while s_done is held by another thread
}
// do some stuff in a thread
// Later:
s_done.clear(); // Sets s_done to false so the thread loop will drop out
Although I recommend using an RAII holder so you can return
or throw
mid-function and the lock will be automatically released.
ATOMIC_FLAG_INIT
is false
because the value of an atomic_flag
is usually interpreted as indicating whether some resource is being held exclusively by a thread. At program start, there is no such thread, indeed the associated resource may not have even been initialized. So false
would be the appropriate initial value.
As for intializing to true
, the standard provides no guarantee that it's even possible to assign a boolean value to an atomic_flag
.
Upvotes: 4
Reputation: 231
An atomic flag which is not initialized with ATOMIC_FLAG_INIT
(or { 0 } ) is in an indeterminate state.
What you could do, to solve your problem is this:
std::atomic_flag lock = ATOMIC_FLAG_INIT;
Now acquire the lock:
while (lock.test_and_set(std::memory_order_acquire))
; // ...
And release it afterwards:
lock.clear(std::memory_order_release);
This is what is called a spin-lock
.
Upvotes: 2
Reputation: 409166
You could always call test_and_set
before starting the thread.
Upvotes: 5