写在前面:本回答是简单线程池的讲解和实现:下个版本的线程池在这个回答里
目录
5.任务存放到任务队列中并使用 sem_post( ) 通知 sem_wait( ) ;
1.写出一个单例
class Threadpool
{
private:
Threadpool(){}
static Threadpool threadpool;
public:
static Threadpool* getInstance(){ return &threadpool; }
};
Threadpool Threadpool::threadpool;
其中最容易忽视的一句是:Threadpool Threadpool::threadpool;
2.设计函数
public:
void start();
void addTask(Task task);
private:
void runTask();
//用于给start绑定
3.设计一个线程池,一个任务队列
std::vector<std::thread> threadList;//线程池
//任务队列
using Task = std::function<void()>;
std::queue<Task> taskQueue;
4.使用Linux信号量
::sem_t taskSem;
::sem_init(&taskSem, 0, 0);
::sem_post(&taskSem);
::sem_wait(&taskSem);
5.任务存放到任务队列中并使用 sem_post( ) 通知 sem_wait( ) ;
taskQueue.push(task);
::sem_post(&taskSem);
//信号量+1
6.收到通知,从任务队列中取出任务并执行
::sem_wait(&taskSem);
//收到通知开始执行
Task task = taskQueue.front();
//拿到第一个任务
taskQueue.pop();
//丢弃第一个任务
task();
//执行第一个任务
7.开启线程池,往线程池里添加N个线程
for(int i = 0; i < threadNums; ++i)
{
threadList.emplace_back(std::thread(&Threadpoll::runTask, this));
}
8.附源码
#include <semaphore.h>
#include <iostream>
#include <chrono>
#include <thread>
#include <functional>
#include <vector>
#include <queue>
::sem_t taskSem;
int threadNums = 10;
class Threadpool
{
private:
Threadpool()
{
::sem_init(&taskSem, 0, 0);
}
static Threadpool threadpool;
private:
std::vector<std::thread> threadList;
using Task = std::function<void()>;
std::queue<Task> taskQueue;
public:
static Threadpool* getInstance(){ return &threadpool; }
void start()
{
for(int i = 0; i < threadNums; i++)
{
threadList.emplace_back(std::thread(Threadpool::runTask, this));
}
}
void addTask(Task task)
{
taskQueue.push(task);
::sem_post(&taskSem);
}
private:
void runTask()
{
::sem_wait(&taskSem);
Task task = taskQueue.front();
taskQueue.pop();
task();
}
};
Threadpool Threadpool::threadpool;
//这句话很重要
9.测试
int main()
{
auto threadpool = Threadpool::getInstance();
threadpool->start();
while(true)
{
std::this_thread::sleep_for(std::chrono::seconds(2));
threadpool->addTask(
[](){std::cout << "addTask" << std::endl;}
);
}
return 0;
}
10.还需完善的地方
本例子迭代过两次:实现了
- linux函数前面加了::,
- task改为Task,
- 绑定函数使用了lambda表达式,
- 去除using namespace std;
- 使用了更加规范的命名方式
- 注意了单例模式必须要在类外声明出来一个实例,且目前不能为指针
没有考虑
- 单例模式的线程安全,这是一个饿汉单例模式
- 没有使用C++11的条件变量,C++11条件变量的实现
- thread没有join,而且去除while(true)会出现bug
- 不理解C++线程的join和notify究竟在上面时候使用