Abruzzo Forte e Gentile
Abruzzo Forte e Gentile

Reputation: 14869

locking with compare and swap on a boolean

I am experimenting the atomic_compare_and_swap function to do a basic lock on a std::atomic<bool>.

The behaviour I was expecting is that the second thread i.e Consume would remain blocked in the while loop at the beginning of Access::get() for all the time the atomic lock_ is set to true.

Due to the sleeps I've introduced it is always the first thread Produce to set the atomic to true to prevent the second thread to proceed.

Unfortunately this is not the case and I can see that the second thread executes immediately and doesn't remain blocked at all.

What am I doing wrong?

I am using g++4.9 on Lubuntu

class Access
{
  atomic<bool> lock_;
  bool         UNLOCKED_;

public:
  Access() : lock_(false), UNLOCKED_(false){}

  void set()
  {
    // lock
    while(!atomic_compare_exchange_strong(&lock_, &UNLOCKED_, true)) {}                 
    this_thread::sleep_for(std::chrono::seconds(20));      
    cout << "set" << endl;   
  }

  void get()
  {
    // lock
    while(!atomic_compare_exchange_strong(&lock_, &UNLOCKED_, true)){} 
    cout << "get" << endl;        
  }
};

Access gTest; // global

void Produce() { gTest.set(); }

void Consume() { gTest.get(); }

int main() {
  thread producer(Produce);
  this_thread::sleep_for(std::chrono::seconds(3));
  thread consumer(Consume);
  producer.join();
  consumer.join();
  return 0;
}

Upvotes: 0

Views: 744

Answers (1)

Alejandro
Alejandro

Reputation: 3082

When the producer thread executes set() and the CAS loop, it will see that the value of UNLOCKED_ and lock_ are the same (false), sets lock_ to true, and returns true. Thus,the loop exits and this thread waits for 20 seconds.

At the same time, the 3 second delay you imposed with

this_thread::sleep_for(std::chrono::seconds(3));

in main() is still ticking and when it expires, the consumer thread executes get() and the CAS loop will first see that UNLOCKED_ is false but lock_ is true (because it was set by the producer), and so it updates the value of UNLOCKED_ to true and spins again. On the next iteration of the CAS loop, it will see that both lock_ and UNLOCKED_ are now true (UNLOCKED_ was set in the previous iteration), and the loop breaks out.

Upvotes: 2

Related Questions