什么是自旋锁
自旋锁指的是当一个线程在获取锁的时候,如果锁已经被其他线程所获取,那么该线程就将进入一个循环,不断的去判断自身是否能够获得锁 ,直到该线程获得了锁,线程才会退出循环。
自旋锁与互斥锁一样是一个为了实现对共享资源的保护而提出的锁机制,都是为了解决对某项资源的互斥使用,它们保证了在并发过程中,该共享资源在任意一个时间端都只有一个拥有者,但是与互斥锁不同的是,自旋锁在共享资源已经被占用的情况下,该线程不会进入阻塞状态,如果自旋锁已经被其他线程所占有,此时试图调用自旋锁将进入循环状态来查看是否能不能获得该锁,而这本身也是由于两者在调度机制上有所不同所造成的。
注意: 未获取锁的线程一直没有休眠处于活跃状态,虽然它本身并不执行什么工作,但是它依旧会消耗cpu,我们称这种状态叫busy waitting
示例代码
#include <iostream> #include <atomic> #include <thread> using namespace std; class CAS { private: std::atomic<bool> flag; public: CAS():flag(false){} CAS(const CAS&)=delete; CAS& operator =(const CAS&)=delete; void lock() { bool expect=false; while(!flag.compare_exchange_strong(expect,true)) //判断能否获得锁 { expect=false; // 失败后,再次尝试 } } void unlock() { flag.store(false); //解锁 } }; int sum=0; CAS cas; void fun() { for(int i=0;i<10;i++) { cas.lock(); cout<<"sum:"<<sum++<<endl; cas.unlock(); } } int main() { std::thread t1(fun); std::thread t2(fun); t1.join(); t2.join(); return 0; }
编译的makefile
all: demo1 demo1: 自旋锁.cpp g++ -pthread 自旋锁.cpp -std=c++11 -o demo1 clean: rm -f demo1
输出结果:
sum:0 sum:1 sum:2 sum:3 sum:4 sum:5 sum:6 sum:7 sum:8 sum:9 sum:10 sum:11 sum:12 sum:13 sum:14 sum:15 sum:16 sum:17 sum:18 sum:19
我们可以看到并不是两个线程互相干扰,而是依次递增。当获得锁的线程还未结束时,另一个线程要进入获取锁时,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,(即expect为false,flag为true,返回false,一直进入while循环),直到获取到锁才会退出循环。当一个线程退出时,另外一个在等待的线程将会立即进入,减少线程由用户态到内核态的转换。
总结
- 自旋锁与互斥锁都是一种共享资源保护机制
- 自旋锁的请求者状态始终为活跃的,而互斥锁则是阻塞的
- 自旋锁如果持有锁的时间太长,则会导致其它等待获取锁的线程耗尽CPU。
- 自旋锁本身无法保证公平性,同时也无法保证可重入性。
结语
本篇篇章有限,简单介绍一些互斥锁的使用,在下一篇文章中我们将
以日志服务部分为例,剖析以下自旋锁在多线程程序中的使用。