14、線程池
1、爲什麼需要線程池
-
服務器都具有一個共同點:單位時間內必須處理很多併發的連接請求,但處理時間卻相對較短.
-
傳統多線程方案中我們採用的服務器模型則是一旦接受到請求之後,即創建一個新的線程,由該線程執行任務.任務執行完畢後,線程退出,這就是是"即時創建,即時銷燬"的策略.
-
儘管與創建進程相比,創建線程的時間已經大大的縮短,但是如果提交給線程的任務是執行時間較短,而且執行次數及其頻繁,那麼服務器將處於不停的創建線程,銷燬線程的狀態.
-
線程池是採用多線程解決方案來提高系統性能的一個最爲出色的模型,它通過預創建一定數量的工作線程來對系統進行併發處理,使得系統的運行效率提高.因爲線程池能使得系統採用較爲輕量的,可控的系統資源實現系統併發處理能力的最大化,所以許多應用軟件都採用了線程池模型.
-
通常線程池所允許的併發線程具有上界的,如果同時需要併發的線程數超過上界,那麼一部分線程將等待.而傳統方案中,如果同時請求數據爲200,那麼最壞情況下,系統可能需要產生200個線程.儘管這不是一個很大的數目,但是也有系統達不到這個要求.
-
線程池模型有許多種,常見的有三種:
-
任務隊列控制的線程池模型,
-
工作線程控制的線程池模型,
-
主控線程控制的線程池模型.
-
2、任務隊列控制的線程池模型
任務隊列控制的線程模型主要是通過任務隊列上的信號來控制線程池中的線程調度。
3、 線程池適合場合
-
事實上,線程池並不是萬能的。它有其特定的使用場合。線程池致力於減少線程本身的開銷對應用所產生的影響,這是有前提的,前提就是線程本身開銷與線程執行任務相比不可忽略。
-
如果線程本身的開銷相對於線程任務執行開銷而言是可以忽略不計的,那麼此時線程池所帶來的好處是不明顯的,比如對於FTP服務器以及Telnet服務器,通常傳送文件的時間較長,開銷較大,那麼此時,我們採用線程池未必是理想的方法,我們可以選擇“即時創建,即時銷燬”的策略。
-
總之線程池通常適合下面的幾個場合:
-
(1) 單位時間內處理任務頻繁而且任務處理時間短
-
(2) 對實時性要求較高。如果接受到任務後在創建線程,可能滿足不了實時要求,因此必須採用線程池進行預創建。
-
(3) 必須經常面對高突發性事件,比如Web服務器,如果有足球轉播,則服務器將產生巨大的衝擊。此時如果採取傳統方法,則必須不停的大量產生線程,銷燬線程。此時採用動態線程池可以避免這種情況的發生
-
4、線程池C++版本
//CPthreadPool.h
#ifndef _CPTHREADPOOL_H_
#define _CPTHREADPOOL_H_
#include <stdio.h>
#include <pthread.h>
#include <list>
#include <iostream>
#include <string.h>
#include "CPthreadCond.h"
#include "CTask.h"
class CPthreadPool
{
public:
CPthreadPool(int minpthread, int maxpthread, int timeout = -1);
//~CPthreadPool();
void create_pthread();
static void *hander(void *arg);
void addtask(CTask *data);
int inowpthread;
int waitpthread;
int maxpthread;
int minpthread;
int timeout;
CPthreadCond cond;
list<CTask *>hander_list;
};
#endif
//CPthreadPool.cpp
#include "CPthreadPool.h"
CPthreadPool::CPthreadPool(int minpthread, int maxpthread, int timeout)
{
this->timeout = timeout;
this->minpthread = minpthread;
this->maxpthread = maxpthread;
this->inowpthread = 0;
this->waitpthread = 0;
this->cond.lock();
for(int i = 0; i < this->minpthread; i++)
{
this->create_pthread();
}
this->cond.unlock();
}
void CPthreadPool::create_pthread()
{
this->inowpthread++;
pthread_t pth = 0;
pthread_create(&pth, NULL, hander, (void *)this);
//printf("create %d pthread\n", this->inowpthread);
}
void *CPthreadPool::hander(void *arg)
{
pthread_detach(pthread_self());
CPthreadPool *pool = (CPthreadPool *)arg;
while(1)
{
pool->cond.lock();
if(!pool->hander_list.empty())//Get one task and do it.
{
CTask *task = pool->hander_list.front();
pool->hander_list.pop_front();// Remove from task list.
pool->cond.unlock();
task->Run();
delete task;
}
else
{
pool->waitpthread++;
if(pool->cond.timewait(pool->timeout))
{
pool->waitpthread--;
pool->cond.unlock();
if(pool->inowpthread > pool->minpthread)
{
//cout << 444 << pool->inowpthread << pool->minpthread << endl;
pool->inowpthread--;
break;
}
}
else
{
//cout << 200 <<endl;
pool->waitpthread--;
pool->cond.unlock();
}
}
}
pthread_exit(NULL);
}
void CPthreadPool::addtask(CTask *data)
{
hander_list.push_back(data);
if(this->waitpthread > 0)
{
this->cond.signal();
//cout << "喚醒\n" << endl;
}
else if(this->inowpthread < this->maxpthread)
{
this->create_pthread();
//cout << "創建線程!\n" << this->inowpthread << endl;
}
}