C++11中已经添加了跨平台的thread相关工具,在一些轻量级使用场景中,使用std::thread无疑会给我们带来很多方便。这里使用它实现了一个简单的线程池:
EasyThreadPool.h#ifndef _EASY_THREAD_POOL_H_
#define _EASY_THREAD_POOL_H_
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <vector>
#include <queue>
#include <functional>
class EasyThreadPool
{
private:
using Task = std::function<void()>;
public:
EasyThreadPool(size_t numThreads = std::thread::hardware_concurrency());
~EasyThreadPool();
//提交任务
void PostTask(const Task &);
private:
std::vector<std::thread> _threads;
std::queue<Task> _tasks;
std::mutex _mutex;
std::condition_variable _cv;
std::atomic<bool> _isDone; //是否已停止加入新任务
std::atomic<bool> _taskEmpty; //任务队列是否已空
void RunThreadWorker();
bool GetTask(Task&);
};
#endif // _EASY_THREAD_POOL_H_
EasyThreadPool.cpp
#include "EasyThreadPool.h"
#include <iostream>
EasyThreadPool::EasyThreadPool(size_t numThreads) : _isDone(false), _taskEmpty(true)
{
try
{
for (size_t i = 0; i < numThreads; i++)
{
_threads.push_back(std::thread(&EasyThreadPool::RunThreadWorker, this));
}
}
catch (...)
{
_isDone.store(true);
throw;
}
}
EasyThreadPool::~EasyThreadPool()
{
_isDone.store(true);
//唤醒所有线程
_cv.notify_all();
for (std::thread &thread : _threads)
{
if (thread.joinable())
{
thread.join();
}
}
}
void EasyThreadPool::PostTask(const Task &task)
{
if (_isDone)
{
std::cout << "The threadPool has been stop!" << std::endl;
}
else
{
std::unique_lock<std::mutex> lock(_mutex);
_cv.wait(lock, [this] { return !_isDone; });
_tasks.push(task);
_taskEmpty.store(false);
//唤醒一个线程去执行
_cv.notify_one();
}
}
void EasyThreadPool::RunThreadWorker()
{
Task task;
//确保任务执行完成后再销毁
while (!_isDone || !_taskEmpty)
{
if (GetTask(task))
{
task();
}
else
{
//暂停一段时间,给别的线程机会
std::this_thread::yield();
}
}
}
bool EasyThreadPool::GetTask(Task &task)
{
std::unique_lock<std::mutex> lock(_mutex);
//不满足条件会阻塞
_cv.wait(lock, [this] { return !_taskEmpty || _isDone; });
if (!_tasks.empty())
{
task = std::move(_tasks.front());
_tasks.pop();
_taskEmpty.store(_tasks.empty());
return true;
}
return false;
}
测试实例
// test.cpp
#include "EasyThreadPool.h"
#include <iostream>
void PrintInfo()
{
std::cout << std::this_thread::get_id() << ": Test" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
int main()
{
EasyThreadPool pool(10);
int i = 0;
while (i++ < 100)
{
pool.PostTask(PrintInfo);
}
return 0;
}
在Linux下使用g++编译:
g++ test.cpp EasyThreadPool.h EasyThreadPool.cpp -o test --std=c++11 -lpthread
线程池的实现无非就是生产者-消费者模型。使用C++11实现线程池的好处显而易见,相比C,它非常简洁,只有100余行代码就可以搞定。不过它涉及到的锁等线程同步的知识任然很有代表性。
源码地址:EasyThreadPool