一.线程池是什么?
维持和管理固定数量线程的池式结构
1.为什么要固定线程数量?
a.线程数量继续增加,由于系统资源的限制,不在带来性能的提升,反而带来负担
b.避免频繁的创建和销毁
2.线程池的组成部分:
固定数量的线程
队列(先进先出+锁)
3.固定多少数量的线程 ?从任务的类型出发 + cpu核心数
a.cpu密集型(用户态执行) cpu核心数
b.io密集型(网络io 以及 磁盘 io, 用户态到内核态的切换 ) 2*cpu核心数 +2
4.为什么用线程池?
某类任务特别耗时,严重影响该线程处理其他任务
二、线程池实现
//thrd_pool.h
//简单实现
#include <queue>
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
class Task
{
public:
void process();
};
class ThreadPool {
// ...
public:
ThreadPool(int thread_count = 1);
void push_task(Task &task);
static void work(void *arg);
void run();
~ThreadPool();
private:
// 任务队列相关
std::queue<Task> m_taskQueue; // 任务队列
std::mutex m_mutex; // 互斥量
std::condition_variable m_condition; // 条件变量
std::vector<std::thread> m_threads; // 线程
};
//thrd_pool.cpp
#include "thrd_pool.h"
int g_num = 0;
void Task::process()
{
printf("%d,%lu\n",++g_num,pthread_self());
}
ThreadPool::ThreadPool(int thread_count)
{
if(thread_count <= 0) return;
for(int i = 0;i<thread_count;i++)
{
m_threads.push_back(std::thread(work,this));
}
}
void ThreadPool::push_task(Task &task)
{
std::lock_guard<std::mutex> lck(m_mutex);
m_taskQueue.push(task);
m_condition.notify_one(); //有任务唤醒
}
void ThreadPool::work(void *arg)
{
printf("开启线程=%lu\n",pthread_self());
ThreadPool *thiz = (ThreadPool *)arg;
thiz->run();
}
void ThreadPool::run()
{
while(1)
{
std::unique_lock<std::mutex> lck(m_mutex); //构造时会执行lock()->m_mutex.lock(),析构时unlock()->m_mutex.unlock()
while(m_taskQueue.empty()) //防止虚假唤醒
{
m_condition.wait(lck); //队列为空 阻塞
//wait函数主要做三件事 1.解锁 m_mutex.unlock() 2.阻塞 3.唤醒时加锁m_mutex.lock()
}
Task task = m_taskQueue.front();
m_taskQueue.pop();
task.process();
}
}
ThreadPool::~ThreadPool()
{
for (auto &thread : m_threads)
thread.join();
}
static void product_thread(void* arg)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
ThreadPool *pool = (ThreadPool*)arg;
for(int i = 0;i<100;i++)
{
Task task;
pool->push_task(task);
}
}
int main()
{
ThreadPool pool(8);
std::this_thread::sleep_for(std::chrono::seconds(1));
//生产者线程
for(int i=0;i<3;i++)
{
std::thread(product_thread,&pool).detach();
}
return 0;
}