湖南省住建厅官方网站建设干校,inove wordpress,小生意是做网站还是公众号,wordpress 指定网址1.线程池 线程池是由服务器预先创建的一组子线程#xff0c;线程池中的线程数量应该和 CPU 数量差不多。线程池中的所有子线程都运行着相同的代码。当有新的任务到来时#xff0c;主线程将通过某种方式选择线程池中的某一个子线程来为之服务。相比与动态的创建子线程#x…1.线程池 线程池是由服务器预先创建的一组子线程线程池中的线程数量应该和 CPU 数量差不多。线程池中的所有子线程都运行着相同的代码。当有新的任务到来时主线程将通过某种方式选择线程池中的某一个子线程来为之服务。相比与动态的创建子线程选择一个已经存在的子线程的代价显然要小得多。至于主线程选择哪个子线程来为新任务服务则有多种方式 ① 主线程使用某种算法来主动选择子线程。最简单、最常用的算法是随机算法和 Round Robin轮流选取算法但更优秀、更智能的算法将使任务在各个工作线程中更均匀地分配从而减轻服务器 的整体压力。 ② 主线程和所有子线程通过一个共享的工作队列来同步子线程都睡眠在该工作队列上。当有新的任务到来时主线程将任务添加到工作队列中。这将唤醒正在等待任务的子线程不过只有一个子线程将获得新任务的”接管权“它可以从工作队列中取出任务并执行之而其他子线程将继续睡眠在工作队列上。 线程池中的线程数量最直接的限制因素是中央处理器(CPU)的处理器(processors/cores)的数量N 如果你的CPU是4-cores的对于CPU密集型的任务(如视频剪辑等消耗CPU计算资源的任务)来说那线程池中的线程数量最好也设置为4或者1防止其他因素造成的线程阻塞对于IO密集型的任务一般要多于CPU的核数因为线程间竞争的不是CPU的计算资源而是IOIO的处理一般较慢多于cores数的线程将为CPU争取更多的任务不至在线程处理IO的过程造成CPU空闲导致资源浪费。
空间换时间浪费服务器的硬件资源换取运行效率。池是一组资源的集合这组资源在服务器启动之初就被完全创建好并初始化这称为静态资源。当服务器进入正式运行阶段开始处理客户请求的时候如果它需要相关的资源可以直接从池中获取无需动态分配。当服务器处理完一个客户连接后可以把相关的资源放回池中无需执行系统调用释放资源。
1.1 线程池类定义
// 线程池类将它定义为模板类是为了代码复用模板参数T是任务类
templatetypename T
class threadpool {
public:/*thread_number是线程池中线程的数量max_requests是请求队列中最多允许的、等待处理的请求的数量*/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; // 描述线程池的数组大小为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;
};
1.2 线程池创建与回收
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_threads(NULL) {if((thread_number 0) || (max_requests 0) ) {throw std::exception();}// 线程id初始化m_threads new pthread_t[m_thread_number];if(!m_threads) {throw std::exception();}// 创建thread_number 个线程并将他们设置为脱离线程。for ( int i 0; i thread_number; i ) {printf( create the %dth thread\n, i);// 循环创建线程并将工作线程按要求进行运行if(pthread_create(m_threads i, NULL, worker, this ) ! 0) {delete [] m_threads;throw std::exception();}// 将线程进行分离后不用单独对工作线程进行回收if( pthread_detach( m_threads[i] ) ) {delete [] m_threads;throw std::exception();}}
}template typename T
threadpool T ::~threadpool() {delete [] m_threads;m_stop true;
}
1.3 向请求队列中添加任务
通过list容器创建请求队列向队列中添加任务时通知互斥锁保证线程安全添加完成后通过信号量提醒有任务要处理最后注意线程同步。
template typename T
bool threadpool T ::append( T* request )
{// 操作工作队列时一定要加锁因为它被所有线程共享。m_queuelocker.lock();// 根据硬件预先设置请求队列的最大值if ( m_workqueue.size() m_max_requests ) {m_queuelocker.unlock();return false;}// 添加任务m_workqueue.push_back(request);m_queuelocker.unlock();// 信号量提醒有任务要处理m_queuestat.post();return true;
}
1.4 线程处理函数
内部访问私有成员函数run,完成线程处理
template typename T
void* threadpool T ::worker( void* arg )
{// 将参数强转为线程池类调用成员方法threadpool* pool ( threadpool* )arg;pool-run();return pool;
}
1.5 run执行任务
主要实现工作线程从请求队列中取出某个任务进行处理注意线程同步
template typename T
void threadpool T ::run() {while (!m_stop) {// 信号量等待m_queuestat.wait();// 被唤醒后先加互斥锁m_queuelocker.lock();if ( m_workqueue.empty() ) {m_queuelocker.unlock();continue;}// 从请求队列中取出第一个任务T* request m_workqueue.front();m_workqueue.pop_front();m_queuelocker.unlock();if ( !request ) {continue;}// process模板类中的方法这里是http类进行处理request-process();}}
1.6 注意事项【总结来源两猿社的最新版Web服务器项目详解 - 03 半同步半反应堆线程池下】
pthread_create的函数原型
#include pthread.h
int pthread_create (pthread_t *thread_tid,//返回新生成的线程的idconst pthread_attr_t *attr,//指向线程属性的指针通常设置为NULLvoid * (*start_routine) (void *),//处理线程函数的地址void *arg);//start_routine()中的参数
在 pthread_create函数原型中的第三个参数为函数指针指向处理线程函数的地址。且该函数为静态函数所以在处理线程函数为类成员函数时需要将其设置为静态成员函数。
// 线程池类将它定义为模板类是为了代码复用模板参数T是任务类
templatetypename T
class threadpool {
private:/*工作线程运行的函数它不断从工作队列中取出任务并执行之*/static void* worker(void* arg);
public:...
};
【原因】
pthread_create的函数原型中的第三个参数的类型为函数指针指向的线程处理函数参数类型为void *。线程函数若为类成员函数则this指针会作为默认参数被传进函数中无法和线程函数参数(void *)匹配无法编译。由于静态成员函数里面没有this指针能解决线程函数参数void*匹配问题。
完整代码
threadpool.h
#ifndef THREADPOOL_H
#define THREADPOOL_H#include list
#include cstdio
#include exception
#include pthread.h
#include locker.h// 线程池类将它定义为模板类是为了代码复用模板参数T是任务类
templatetypename T
class threadpool {
public:/*thread_number是线程池中线程的数量max_requests是请求队列中最多允许的、等待处理的请求的数量*/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; // 描述线程池的数组大小为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_threads(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();}// 创建thread_number 个线程并将他们设置为脱离线程。for ( int i 0; i thread_number; i ) {printf( create the %dth thread\n, i);if(pthread_create(m_threads i, NULL, worker, this ) ! 0) {delete [] m_threads;throw std::exception();}if( pthread_detach( m_threads[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.unlock();return false;}m_workqueue.push_back(request);m_queuelocker.unlock();m_queuestat.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_workqueue.empty() ) {m_queuelocker.unlock();continue;}T* request m_workqueue.front();m_workqueue.pop_front();m_queuelocker.unlock();if ( !request ) {continue;}request-process();}}#endiflocker.h
#ifndef LOCKER_H
#define LOCKER_H#include exception
#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 signal() {return pthread_cond_signal(m_cond) 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(int num) {if( sem_init( m_sem, 0, num ) ! 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