1、线程池
一种基于池化思想管理和使用线程的机制,将多个线程预先储存在池子里,当有任务出现时可以避免重新创造和销毁线程所带来的性能开销。
2、IO模型
1)阻塞IO模型: 应用程序的进程发起IO调用,如果内核数据没有准备好 ,应用进程一直阻塞等待,直到内核数据准备好了,从内核态拷贝到用户态,才返回成功提示。
2)非阻塞IO模型:应用程序的进程发起IO调用,如果内核数据没有准备好,就返回错误信息,用户进程无需等待,而是通过轮询的方式等待请求结果,数据准备好,从内核缓冲区拷贝到用户区,返回成功提示;
3)IO多路复用
系统提供一类可以同时监控多个fd文件描述符的函数epoll、select、poll,任何一个返回内核数据就绪,应用进程再发起系统调用。
4)信号驱动IO
用户进程向内核发送一个信号, 不用阻塞,当内核数据准备好后,在通过信号通知应用进程数据可读,应用进程收到信号后立即去处理。
5)异步IO模型
应用进程发出系统调用后,立刻返回提交成功的提示,等待内核数据处理好将数据拷贝到用户缓冲区后,发送信号通知用户进程IO操作执行完毕。aio_read和aio_write
3、事件处理模式
1)reactor
- 主线程往epoll内核事件表中注册socket的读就绪事件
- 主线程调用epoll_wait等待socket上有数据可读
- 当socket上有数据可读时,epoll_wait通知主线程,主线程将可读事件放入请求队列
- 睡眠在请求队列上的某个工作线程被唤醒,从socket读取数据,并处理客户请求,然后往epoll内核事件表中注册该socket上的写就绪事件
- 主线程调用epoll_wait等待socket可写
- 当socket可写时,epoll_wait通知主线程,主·线程将可写事件放入请求队列
- 睡眠在请求队列上的工作线程被唤醒,往socket上写入服务器处理客户端请求的结果
2)preactor
- 主线程调用epoll内核事件表注册socket上的读就绪事件;
- 主线程调用epoll_wait等待socket上有数据可读
- 当socket上有数据可读时,epoll_wait通知主线程,主线程从socket上循环上读取数据,将读取的数据封装成一个请求对象并插入请求队列
- 睡眠在请求队列上的工作线程被唤醒,它获取请求对象并处理客户请求,然后往epoll内核事件表中注册该socket上的写就绪事件;
- 主线程调用epoll_wait等待socket可写;
- 当socket上有数据可写时,epoll_wait通知主线程,主线程往socket上写入服务器处理请求的结果。
4、locker.h
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
//锁类
class locker
{
public:
locker(){
if(pthread_mutex_init(&m_mutex,NULL)!=0)
{
throw std::exception();
}
}
~locker(){
pthread_mutex_destroy(&m_mutex);
}
bool lock(){
return pthread_mutex_lock(&m_mutex)==0;
}
bool unlock(){
return pthread_mutex_unlock(&m_mutex)==0;
}
//获取锁
pthread_mutex_t *get(){
return &m_mutex;
}
private:
pthread_mutex_t m_mutex;
};
//条件变量类
class cond
{
public:
cond(){
if(pthread_cond_init(&m_cond,NULL)!=0){
throw std::exception();
}
}
~cond(){
pthread_cond_destroy(&m_cond);
}
bool wait(pthread_mutex_t *m_mutex){
int ret=0;
ret=pthread_cond_wait(&m_cond,m_mutex);
return ret==0;
}
bool timewait(pthread_mutex_t *m_mutex,struct timespec t){
int ret=0;
ret=pthread_cond_timedwait(&m_cond,m_mutex,&t);
return ret==0;
}
bool broadcast(){
return pthread_cond_broadcast(&m_cond)==0;
}
private:
pthread_cond_t m_cond;
};
//信号量类
class sem{
public:
sem(){
if(sem_init(&m_sem,0,0)!=0){
throw std::exception();
}
}
~sem(){
sem_destroy(&m_sem);
}
bool wait(){
return sem_wait(&m_sem)==0;
}
bool post(){
return sem_post(&m_sem)==0;
}
private:
sem_t m_sem;
};
#endif
5、threadpool.h
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include <list>
#include <cstdio>
#include <exception>
#include <pthread.h>
#include "locker.h"
#include <stdio.h>
#include <cstdio>
template<typename T>
class threadpool
{
public:
threadpool(int thread_number=8;int max_requests=10000);
~threadpool();
bool append(T *request);
private:
static void* worker(void *arg);//共有线程工作函数
void run();//私有线程工作函数
private:
int m_thread_number;//线程池中的线程数量
pthread_t *m_threads;//线程池数组
int m_max_requests;//请求队列中,最多允许的等待请求数量
std::list<T*> m_workqueue;//请求队列
locker m_queuelocker;//保护请求队列的互斥锁
sem m_queuestat;//请求队列的信号量
bool m_stop;//是否结束线程标志位
};
template<typename T>
threadpool<T>::threadpool(int thread_number,int max_requests):
m_thread_number(thread_number),m_max_requests(max_requests),
m_stop(false),m_thread(NULL){
if((thread_number<=0)||(max_requests<=0)){
throw std::exception();
}
m_threads=new pthread_t[m_thread_number];
if(!m_threads){
throw std::exception();
}
for(int i=0;i<thread_number;++i){
printf("create the %dth thread\n",i);
if(pthread_create(m_thread+i,NULL,worker,this)!=0){
delete[] m_threads;
throw std::exception();
}
if(pthread_detach(m_thread[i])){
delete[] m_threads;
throw std::exception();
}
}
}
template<typename T>
threadpool<T>::~threadpool()
{
delete[] m_threads;
m_stop=true;
}
template<typename T>
bool threadpool<T>::append(T *request){
m_queuelocker.lock();
if(m_workqueue,size()>m_max_requests)
{
m_queuelocker.unlook();
return false;
}
m_workqueue.push_back(request);
m_queuelocker.lock();
m_queuelocker.post();
return true;
}
template<typename T>
void* threadpool<T>::worker(void *arg){
threadpool *pool=(threadpool *)arg;
pool->run();
return pool;
}
template<typename T>
void threadpool<T>::run(){
while (!m_stop)
{
m_queuestat.wait();
m_queuelocker.lock();
if(m_workerqueue.empty()){
m_queuelocker.unlook();
continue;
}
T* request=m_workqueue.front();
m_workqueue.pop_front();
m_queuelocker.unlock();
if(!request){
continue;
}
request->process();
}
}
#endif