自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,因此使用这种锁会造成busy-waiting,也就是CPU不断的进行检测操作,而无法处理其他任务。
本文使用原子类型atomic_flag来实现自旋锁。atomic_flag 一种简单的原子布尔类型,只支持两种操作:
1、test-and-set(): 检测flag是否为true,如果不为true,则设置为true。如果为true,则不进行处理。
2、clear():清除对flag的设置
之所以利用这种类型来实现自旋锁,最重要的点在于对其对象的操作是完全是原子操作。
关于atomic_flag更多的介绍信息可见以下的链接:
1、cplusplush-atomic_flag
2、C++11 并发指南六(atomic 类型详解一 atomic_flag 介绍)
以下是自旋锁的具体实现以及测试代码:
测试使用三个线程同时对一个全局变量进行写操作,在使用自旋锁的情况下,变量的输出完全有序,而在不使用自旋锁的情况下,变量的打印会出现无序的现象。读者可关闭自旋锁进行测试。
#include <iostream>
#include <atomic>
#include <thread>
using namespace std;
// 自旋锁的实现
class spin_lock {
public:
spin_lock() = default;
spin_lock(const spin_lock&) = delete;
spin_lock& operator=(const spin_lock) = delete;
void lock() {
// acquire spin lock
while (flag.test_and_set()) {
}
}
void unlock() {
// release spin lock
flag.clear();
}
private:
atomic_flag flag;
};
int num = 0;
spin_lock splock;
void addFunc() {
for (int i = 0; i < 1000; ++i) {
splock.lock();
++num;
cout << "num = " << num << endl;
splock.unlock();
}
}
int main() {
cout << "程序开始执行" << endl;
thread t1(addFunc);
thread t2(addFunc);
thread t3(addFunc);
t1.join();
t2.join();
t3.join();
return 0;
}
另外,上述实际使用中,我们必须手动调用 unlock() 接口,否则其他线程会因为上锁而等待。这里我们可以使用lock_guard()来实现自动调用lock()和unlock(),当lock_guard()对象离开作用域的时候,其析构函数会自动调用unlock()接口。
是不是又智能了一步~~~~
以下是使用lock_guard()管理atomic_flag对象的过程。注意添加mutex头文件。
#include <iostream>
#include <atomic>
#include <thread>
#include <mutex>
using namespace std;
// 自旋锁的实现
class spin_lock {
public:
spin_lock() = default;
spin_lock(const spin_lock&) = delete;
spin_lock& operator=(const spin_lock) = delete;
void lock() {
// acquire spin lock
while (flag.test_and_set()) {
}
}
void unlock() {
// release spin lock
flag.clear();
}
private:
atomic_flag flag;
};
int num = 0;
spin_lock splock;
void addFunc() {
for (int i = 0; i < 1000; ++i) {
std::lock_guard<spin_lock> lock(splock); // 就是这里不一样!!!
++num;
cout << "num = " << num << endl;
}
}
int main() {
cout << "程序开始执行" << endl;
thread t1(addFunc);
thread t2(addFunc);
thread t3(addFunc);
t1.join();
t2.join();
t3.join();
return 0;
}
谢谢阅读
参考:C++11实现自旋锁