一种线程使用模式,线程过多会带来调度开销,进而影响缓存局部性和整体性能。线程池维护多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价,线程池不仅能保证内核的充分利用,还能防止过分调度,可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量
线程池的应用场景:
1.需要大量的线程来完成任务,且完成任务的时间比较短。WEB服务器完成网页请求这样的任务,使用线程池是非常合适的。因为单个任务小,任务数量巨大,可以想象一个热门网站的点击次数。但对于长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为telnet会话时间比线程的创建时间大多了
2.对性能要求苛刻的应用,比如要求服务器迅速响应客户请求
3.接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间产生大量线程可能使内存达到极限,出现错误

提前申请很多线程,线程处于睡眠状态,当往共享区放入任务后唤起线程拿到任务开始运行。和生产消费类似
类的设计
用一个数组保存所有线程,元素类型是自定义线程类,包含线程tid和名字。队列作为共享数据。一个锁保护共享数据的安全,条件变量保证多个线程访问的同步。start功能创建指定数量的线程,运行指定函数,类内函数默认第一个参数是this指针,但线程函数必须是void*参数,所以这个函数加static。加锁访问,当共享资源为空时线程挂起,否则取出队首的元素交给线程执行,执行前释放锁。放入任务功能,加锁访问,放入成功后唤醒休眠线程
#pragma once
#include <vector>
#include <queue>
#include <pthread.h>
#include <string>
#include <unistd.h>
//换为封装的线程
struct ThreadInfo
{
pthread_t _tid;
std::string _name;
};
template <class T>
class pool
{
static const int defaultnum = 5;
public:
pool(int num = defaultnum)
:_thread(num)
{
pthread_mutex_init(&_mutex, nullptr);
pthread_cond_init(&_cond, nullptr);
}
std::string getname(pthread_t tid)
{
for (auto ch : _thread)
{
if (ch._tid == tid)
{
return ch._name;
}
}
return "None";
}
static void* HandlerTask(void* args)
{
pool<T> *tp = static_cast<pool<T> *>(args);
std::string name = tp->getname(pthread_self());
while (true)
{
pthread_mutex_lock(&(tp->_mutex));
while (tp->_que.empty())
{
pthread_cond_wait(&(tp->_cond), &(tp->_mutex));
}
T t = tp->_que.front();
tp->_que.pop();
pthread_mutex_unlock(&tp->_mutex);
t.run();
printf("%s finsih task:%s\n", name.c_str(), t.getresult().c_str());
sleep(1);
}
}
void start()
{
for (int i = 0; i < _thread.size(); i++)
{
_thread[i]._name = "thread" + std::to_string(i);
pthread_create(&_thread[i]._tid, nullptr, HandlerTask, this);
}
}
void push(const T& x)
{
pthread_mutex_lock(&_mutex);
_que.push(x);
pthread_cond_signal(&_cond);
pthread_mutex_unlock(&_mutex);
}
~pool()
{
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_cond);
}
private:
std::vector<ThreadInfo> _thread;
std::queue<T> _que;
pthread_mutex_t _mutex;
pthread_cond_t _cond;
};
task.hpp
#pragma once
#include <stdio.h>
#include <string>
enum
{
DIVZERO = 1,
UNKNOW
};
std::string g_op = "+-*/";
struct task
{
public:
task()
{}
task(int a, int b, char op)
:_a(a), _b(b), _op(op), _result(0), _exitcode(0)
{}
void run()
{
switch(_op)
{
case '+':
_result = _a + _b;
break;
case '-':
_result = _a - _b;
break;
case '*':
_result = _a * _b;
break;
case '/':
if (_b == 0)
{
_exitcode = DIVZERO;
}
else
{
_result = _a / _b;
}
break;
default:
_exitcode = UNKNOW;
break;
}
//printf("%d+%d结果:%d\n", _a, _b, _a + _b);
}
std::string getresult()
{
std::string str = std::to_string(_a) + _op + std::to_string(_b);
str += "=";
str += std::to_string(_result);
str += " [exit:";
str += std::to_string(_exitcode);
str += "]";
return str;
}
std::string gettask()
{
std::string str = std::to_string(_a) + _op + std::to_string(_b);
return str;
}
private:
int _a;
int _b;
char _op;
int _result;
int _exitcode;
};
main.cc
#include <stdlib.h>
#include <thread>
#include "task.hpp"
#include "ThreadPool.hpp"
#include "Thread.hpp"
int main()
{
srand(time(NULL));
printf("run\n");
pool<task> *pl = new pool<task>(5);
pl->start();
sleep(3);
while (true)
{
// 构建任务
int data1 = rand() % 10;
int data2 = rand() % 10 + 1;
char op = g_op[rand() % 4];
task t(data1, data2, op);
// 交给线程池
printf("task:%s\n", t.gettask().c_str());
pl->push(t);
sleep(1);
}
}
线程类封装
c++11引入了线程类,对底层线程函数做了封装,仍然离不开lpthread库,对原生线程也试着封装,引入自己的功能
线程类保存tid,名字,是否运行,启动时间,需要调用的函数
通过函数指针设置为类成员变量需要调用的函数,生成的线程先调用接口函数,接口函数调用入口函数,入口函数调用函数指针指向的函数。可以通过类模板作为成员变量来引入需要传入的参数
#pragma once
#include <string>
#include <ctime>
#include <pthread.h>
static int num = 1;
typedef void (*callback)();
//模板传参数
class Thread
{
public:
Thread(callback cb)
:_tid(0), _name(""), _time(0), _running(false), _cb(cb)
{}
static void* routine(void* args)
{
Thread *tp = static_cast<Thread *>(args);
tp->entry();
return nullptr;
}
void run()
{
_name = "thread-" + std::to_string(num++);
_time = time();
_running = true;
pthread_create(&_tid, nullptr, routine, this);
}
void join()
{
pthread_join(_tid, nullptr);
}
//传入参数
void entry()
{
_cb();
}
std::string name()
{
return _name;
}
pthread_t gettid()
{
return _tid;
}
uint64_t time()
{
return _time;
}
bool isrunning()
{
return _running;
}
private:
pthread_t _tid;
std::string _name;
uint64_t _time;
bool _running;
callback _cb;
};