一、概要
spinLock的基本原理是如果发现其他人锁着,就一直循环,知道其他人解锁后,再上锁。一般SpinLock适用于锁的时间很短的情况,通过不断判定是否可以加锁,避免适用Mutex这类操作系统锁带来不能锁定时的上下文切换。
二、实现源码
#pragma once
#include <atomic>
#include <thread>
using namespace std;
class SpinLock
{
private:
atomic<bool> _flag;
public:
SpinLock()
{
_flag = false;
}
void lock()
{
bool r = false;
while (!_flag.compare_exchange_strong(r, true)) //如果_flag为false,就把_flag改为true,r改为false,并且保证_flag的获取和修改时原子的
{
r = false;
}
}
void unlock()
{
_flag.store(false);
}
};
class SpinLockTest
{
private:
int count = 0;
int spinCount = 0;
int maxLoop = 10000000;
SpinLock lock;
public:
void doTest()
{
thread thread1([this](){
this->process(); });
thread thread2([this](){
this->process(); });
thread1.join();
thread2.join();
thread thread3([this]() {
this->spinProcess(); });
thread thread4([this]() {
this->spinProcess(); });
thread3.join();
thread4.join();
printf("count=%d spinCount=%d\n", count, spinCount);
}
void process()
{
for (int i = 0; i < maxLoop; i++)
{
count++;
}
}
void spinProcess()
{
for (int i = 0; i < maxLoop; i++)
{
lock.lock();
spinCount++;
lock.unlock();
}
}
};
三、输出结果
count=13795495 spinCount=20000000
三、代码分析
- 从结果看spinLock实现了对spinCount的原子操作,而普通的多线程累加不能保证原子。
- 其中用到了Atomic。Atomic可以实现对基本类型数据的原子读、原子写以及CAS操作。CAS是一种比较交换,当前值和期望值一样时,就交换成目标值。这里涉及到对Atomic值的读和写,单一通过原子读和原子写不能保证整个读写是原子的。幸好,Atomic提供了CAS操作,CAS通过CPU级别的无锁操作,实现了对数据的原子读写,不会导致上下文切换,比Mutex这种操作系统级别的锁有数倍的性能提升。