最近有学习一些关于C++11从语法层面上提供的多线程编程。本来考虑使用C++11的互斥锁来实现线程间的互斥,而C++提供的互斥锁是比较简单的,和Linux的使用没有太大区别。
另一方面,在面试的时候,会涉及一些无锁的互斥手法。比如:在webserver项目中,请求队列的任务在出队和入队上都需要互斥锁。而互斥锁比较重,需要执行系统调用。而系统调用又需要陷入内核态,调度完切换回用户态又需要时间,因此效率较低。
这时候,采用CAS+自旋锁
的手法效率会比较高。
因此,下面的例子借鉴陈硕大神在muduo网络库实现一个迷你版的线程池。在这个线程池中,我们把线程类Thread
和线程池类ThreadPool
进行解耦,让模块与模块之间的耦合度更低。在实现细节上:
其中,ThreadPool
类定义了线程池中的子线程的工作函数runInThread
,这个在muduo网络库
里面其实是开发了个接口给用户进行定义的,但是在这里我们没有提供这个借口,感兴趣的读者可以自行拓展封装。
我们实现了一个CAS
类的自旋锁,其实现使用了C++11提供的原子类atomic
。
#include
#include
#include
#include
#include
#include
using namespace std;
int mutex = 0;
int lock = 1;
int unlock = 0;
class CAS {
public:
CAS() : flag(false) {}
// 上锁
void lock() {
bool expect = false;
// 1. 如果flag的值(锁的值)和期望的值相等,那么将新的值赋给flag,返回true
// 2. 如果flag的值(锁的值)和期望值不相等,那么将flag的值赋给expect,返回false,因此每次都要重置expect
while (!flag.compare_exchange_weak(expect, true)) {
expect = false;
}
}
// 解锁
void unlock() {
flag.store(false);
}
private:
CAS(const CAS&) = delete;
CAS& operator=(const CAS&) = delete;
atomic<bool> flag; // false为解锁状态 true为上锁状态
};
class Thread {
public:
Thread(function<void()> func) : func_(func) {}
thread start() {
thread t(func_);
return t;
}
private:
function<void()> func_;
};
class ThreadPool {
public:
void startPool(int poolSize) {
for (int i = 0; i < poolSize; ++i) {
pool_.push_back(new Thread(bind(&ThreadPool::runInPool, this, i)));
}
for (int i = 0; i < poolSize; ++i) {
handler_.push_back(pool_[i]->start());
}
for (int i = 0; i < poolSize; ++i) {
handler_[i].join();
}
}
private:
// 工作函数
void runInPool(int threadId) {
mutex_.lock();
cout << "Thread start! Thread Id:" << threadId << endl;
mutex_.unlock();
}
vector<Thread*> pool_;
vector<thread> handler_;
CAS mutex_;
};
int main() {
ThreadPool pool;
pool.startPool(10);
return 0;
}