通过比较锁定并交换布尔值

locking with compare and swap on a boolean

我正在试验 atomic_compare_and_swap 函数来对 std::atomic<bool> 进行基本锁定。

我期望的行为是第二​​个线程,即 Consume 将一直阻塞在 Access::get() 开始的 while 循环中,直到原子 [=16] =] 设置为 true

由于 sleeps 我已经介绍过它总是第一个线程 Produce 将原子设置为 true 以防止第二个线程继续进行。

不幸的是,情况并非如此,我可以看到第二个线程立即执行并且根本没有保持阻塞状态。

我做错了什么?

我正在使用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;
}

生产者线程执行set()和CAS循环时,会看到UNLOCKED_lock_的值相同(false),设置lock_ 为真,returns 为真。因此,循环退出,该线程等待 20 秒。

同时,你施加的 3 秒延迟

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

in main() 仍在滴答,当它过期时,消费者线程执行 get() 并且 CAS 循环将首先看到 UNLOCKED_falselock_ 为真(因为它是由生产者设置的),因此它将 UNLOCKED_ 的值更新为 true 并再次旋转。在 CAS 循环的下一次迭代中,它会看到 lock_UNLOCKED_ 现在都是 trueUNLOCKED_ 是在上一次迭代中设置的),然后循环中断出去。