線程池
一、定義:線程池是一種線程使用模式。
二、目的:線程過多會帶來調度開銷,進而影響緩存局部性和整體性能。而線程池維護着多個線程,等待着監督管理者分配可併發執行的任務。這避免了在處理短時間任務時創建與銷燬線程的代價。線程池不僅能夠保證內核的充分利用,還能防止過分調度。可用線程數量應該取決於可用的併發處理器、處理器內核、內存、網絡sockets等的數量。
三、應用場景:
- 需要大量的線程來完成任務,且完成任務的時間比較短。 WEB服務器完成網頁請求這樣的任務,使用線程池技術是非常合適的。因爲單個任務小,而任務數量巨大,你可以想象一個熱門網站的點擊次數。 但對於長時間的任務,比如一個Telnet連接請求,線程池的優點就不明顯了。因爲Telnet會話時間比線程的創建時間大 多了。
- 對性能要求苛刻的應用,比如要求服務器迅速響應客戶請求。
- 接受突發性的大量請求,但不至於使服務器因此產生大量線程的應用。突發性大量客戶請求,在沒有線程池情況下,將產生大量線程,雖然理論上大部分操作系統線程數目最大值不是問題,短時間內產生大量線程可能使內存到達極限,出現錯誤.
四、線程池示例:
功能:1. 創建固定數量線程池,循環從任務隊列中獲取任務對象,
2. 獲取到任務對象後,執行任務對象中的任務接口
- 代碼實現:
/* 線程池 */
#ifndef __M_POOL_H_
#define __M_POOL_H_
#include<stdio.h>
#include<iostream>
#include<queue>
#include<error.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#define MAX_THREAD 5
#define MAX_QUEUE 10
typedef bool (*HandleFunc)(int data);
class MyTask
{
private:
int _data;
HandleFunc _handleFunc;
public:
MyTask(){}
MyTask(int data,HandleFunc handleFunc)
:_data(data)
,_handleFunc(handleFunc) {}
~MyTask(){}
void SetTask(int data,HandleFunc handleFunc)
{
_data = data;
_handleFunc = handleFunc;
}
bool Run()
{
return _handleFunc(_data);
}
};
class MyThreadPool
{
private:
int max_thread; //線程池中最大線程數
int cur_thread; //當前線程池中的線程數
int quitFlag; //線程池中線程退出的標誌
int max_queue; //隊列的最大節點數
std::queue<MyTask> task_list; //任務隊列
pthread_mutex_t mutex; //互斥量
pthread_cond_t empty; //條件變量
pthread_cond_t full; //條件變量
void ThreadLock() //加鎖
{
pthread_mutex_lock(&mutex);
}
void ThreadUnLock() //解鎖
{
pthread_mutex_unlock(&mutex);
}
void ConsumerWait() //消費者等待(爲空則等待)
{
if(quitFlag == true) //所有任務均完成,則線程退出
{
cur_thread--;
pthread_mutex_unlock(&mutex);
printf("Thread[%p] exited.\n",pthread_self());
pthread_exit(NULL);
}
pthread_cond_wait(&empty,&mutex);
}
void ConsumerWake() //喚醒消費者
{
pthread_cond_signal(&empty);
}
void ConsumerWakeAll() //廣播喚醒剩餘所有線程
{
pthread_cond_broadcast(&empty);
}
void ProducterWait() //生產者等待(滿了則等待)
{
pthread_cond_wait(&full,&mutex);
}
void ProducterWake() //喚醒生產者
{
pthread_cond_signal(&full);
}
bool QueueEmpty()
{
return task_list.empty();
}
bool QueueFull()
{
return (task_list.size() == max_queue ? true : false);
}
void QueuePush(MyTask& task) //將task放入任務隊列
{
task_list.push(task);
}
void QueuePop(MyTask* task) //從任務隊列取出task
{
*task = task_list.front();
task_list.pop();
}
public:
MyThreadPool(int maxt = MAX_THREAD,int maxq = MAX_QUEUE)
:max_thread(maxt)
,max_queue(maxq)
{
cur_thread = maxt;
quitFlag = false;
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&empty,NULL);
pthread_cond_init(&full,NULL);
}
~MyThreadPool()
{
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&empty);
pthread_cond_destroy(&full);
}
static void* ThreadFunc(void* arg) //線程執行函數
{
std::cout<<"In ThreadFunc()"<<std::endl;
MyThreadPool* p = (MyThreadPool*)arg;
while(1)
{
p->ThreadLock();
while(p->QueueEmpty()) //任務隊列沒任務
p->ConsumerWait();
MyTask task;
p->QueuePop(&task);
p->ProducterWake();
p->ThreadUnLock();
task.Run();
}
return NULL;
}
bool MyThreadPool_Init() //初始化線程池
{
pthread_t tid;
int ret;
for(int i = 0;i<max_thread;++i) //創建線程
{
ret = pthread_create(&tid,NULL,ThreadFunc,(void*)this);
if(ret != 0) //pthread_create()返回值不爲0說明創建失敗
{
perror("pthread_create");
return false;
}
pthread_detach(tid); //線程分離
}
return true;
}
bool AddTask(MyTask& task) //向任務隊列添加任務
{
ThreadLock();
if(quitFlag == true) //線程不玩了
{
ThreadUnLock();
return false;
}
while(QueueFull()) //任務隊列已滿
ProducterWait();
QueuePush(task);
ConsumerWake();
ThreadUnLock();
return true;
}
void MyThreadPool_Quit() //線程池退出
{
std::cout<<"In MyThreadPool_Quit"<<std::endl;
ThreadLock();
quitFlag = true;
ThreadUnLock();
while(cur_thread > 0) //退出線程池內的所有線程
{
ConsumerWakeAll();
usleep(3000);
}
}
};
bool TaskHandle(int data)
{
srand((unsigned int)time(NULL));
int n = rand()%5;
printf("Thread[%p] is ready to sleep for %d seconds.\n",pthread_self(),n);
sleep(n);
return true;
}
int main()
{
MyThreadPool p;
p.MyThreadPool_Init();
MyTask task[10];
for(int i =0;i<10;++i)
{
task[i].SetTask(i,TaskHandle);
p.AddTask(task[i]);
printf("task[%d] : Add success!\n ",i);
}
p.MyThreadPool_Quit();
return 0;
}
#endif
- 運行之:
- 運行步驟: