这是mhy12345的无锁数据结构教程的第二篇,通过atomic<bool>实现自旋锁。对,你没有听错,用无锁数据结构实现一个锁 >_<
自旋锁,顾名思义,通过自旋来实现线程加锁的工具。一个最简单的demo如下
bool flag = false; void func() { while (!flag); flag = true; //TODO1 flag = false; //TODO2 }
看起来这是一个很机智的做法。程序进入时将一个共享bool变量赋值为true,而在另一个程序准备进入时,检查到该bool变量已经为true了,就放弃进入,开始用while语句自旋。

不过对于一个多线程程序,其他线程可以在任意位置接入,比如这个程序的第4行和第5行不是一个原子操作,倘若这个时候恰好另一个线程获得了控制权,读取到flag值为false,继续执行,但是在释放flag之前控制权有转会了第一个线程,由于第一个线程已经执行了取值操作,也默认flag为false,继续执行,导致受保护数据被重复访问。产生问题。
这时候,一个非常自然的想法就是:我们能不能把对flag的操作换成原子数据类型操作呢?答案是肯定的!
std::atomic<bool> flag = ATOMIC_VAR_INIT(false); void func() { bool expected = false; while(!flag.compare_exchange_weak(expected, true, std::memory_order_acquire)) expected = false; //TODO1 flag.store(false, std::memory_order_release); }
当程序执行到第六行时,准备进入临界区//TODO ,首先判断flag是否为false,如果不是,说明已经有一个程序在临界区中间了。否则将flag赋值为true,自己进入临界区。
一点细节是,如果进入临界区失败,则true值会被赋予expected,这是我们需要在while语句中恢复expected的值。
memory_order是什么呢?请看:无锁数据结构设计 之 详解C++内存顺序(Memory Order)
参考资料:
https://blog.poxiao.me/p/spinlock-implementation-in-cpp11/
http://blog.csdn.net/yockie/article/details/8838661
《无锁数据结构设计 之 通过atomic实现自旋锁》有一个想法