1:简介
本文基于C++11,实现的线程池功能实现相当于java中核心数线程为size,最大线程数为size,任务队列为无界队列的ThreadPoolExecutor线程池,且简化了,直接一次性生产出size数量的线程。凡是继承了Runnable接口的任务都可以提交到该线程池中。任务队列也模仿Java的BlockingQueue阻塞队列。
2:C++版本的BlockingQueue
主要采用C++11的条件变量std::condition_variable来实现。
BlockingQueue.hpp
#include <queue>
#include <mutex>
#include <condition_variable>
/**
* 阻塞队列
* @tparam T 任意类型
*/
template<typename T>
class BlockingQueue {
private:
std::queue<T> queue;//队列
std::mutex mutex;//互斥锁
std::condition_variable conditionVariable;
public:
//把Object加到BlockingQueue里
void put(const T &t) {
std::unique_lock<std::mutex> lock(mutex);//加上互斥锁
queue.push(t);
conditionVariable.notify_one();//释放互斥锁,通知等待线程
}
//取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到BlockingQueue有新的数据被加入
T take() {
std::unique_lock<std::mutex> lock(mutex);//互斥锁加上
if (queue.empty()) {
//若队列为空,则等待互斥锁,当调用wait方法时会unlock
conditionVariable.wait(lock);
}
T t = queue.front();
queue.pop();
return t;
}
};
3:C++版本的Runnable接口
用纯虚函数来表示
Runnable.hpp
class Runnable {
public:
virtual void run() = 0;
};
3:ThreadPoolExecutor
基本思路:基于上面实现的BlockingQueue阻塞队列来实现任务队列,线程池中线程会去任务队列中取任务来执行,如果没任务,则等待,若任务队列中有任务了,则唤醒一个等待线程去执行该任务。
#include <vector>
#include <thread>
#include <algorithm>
#include "BlockingQueue.hpp"
#include "Runnable.hpp"
//相当于ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue workQueue,RejectedExecutionHandler handler)
//corePoolSize:线程池核心线程数量size
//maximumPoolSize:线程池最大线程数量size
//且简化了,直接一次性生产size数量的线程
class ThreadPoolExecutor {
private:
std::vector<std::thread> workers;//线程工作组
BlockingQueue<std::shared_ptr<Runnable>> taskQueue;//任务队列
volatile bool stop;
public:
//构造线程池,同时启动它
ThreadPoolExecutor(int size) : stop(false) {
for (int i = 0; i < size; ++i) {
workers.emplace_back([this] {
while (!stop) {
taskQueue.take()->run();
}
});
}
}
/**
* 提交一个任务
* @param task
*/
void submit(std::shared_ptr<Runnable> task) {
taskQueue.put(task);
}
/**
* 析构的时候需要让线程正常退出
*/
~ThreadPoolExecutor() {
this->stop = true;
//等待run方法正常结束
std::for_each(
workers.begin(),
workers.end(),
[](std::thread &t) { t.join(); }
);
}
};
4:测试代码
main.cpp
#include <iostream>
#include "Runnable.hpp"
#include "ThreadPoolExecutor.hpp"
#include <thread>
#include <memory>
class TestRunnun1 : public Runnable {
public:
void run() {
for (int i = 0; i < 1000; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
if (i % 50 == 0) {
std::cout << "hello!! thread1...." << std::this_thread::get_id() << std::endl;
}
}
std::cout << "hello!! thread1...." << std::this_thread::get_id() << std::endl;
}
};
class TestRunnun2 : public Runnable {
public:
void run() {
for (int i = 0; i < 1000; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
if (i % 50 == 0) {
std::cout << "hello!! thread3...." << std::this_thread::get_id() << std::endl;
}
}
std::cout << "hello!! thread3...." << std::this_thread::get_id() << std::endl;
}
};
int main() {
ThreadPoolExecutor executor(2);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
executor.submit(std::make_shared<TestRunnun1>());
executor.submit(std::make_shared<TestRunnun1>());
executor.submit(std::make_shared<TestRunnun2>());
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
executor.submit(std::make_shared<TestRunnun1>());
executor.submit(std::make_shared<TestRunnun2>());
std::cout << "Hello, World!" << std::endl;
return 0;
}