Matt Clarkson
Matt Clarkson

Reputation: 14416

Why is ATOMIC_FLAG_INIT false?

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

Answers (3)

Casey
Casey

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

Stefan
Stefan

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

Some programmer dude
Some programmer dude

Reputation: 409166

You could always call test_and_set before starting the thread.

Upvotes: 5

Related Questions