本文轉載於:https://blog.csdn.net/ywcpig/article/details/52557080
內存池
平常我們使用new、malloc在堆區申請一塊內存,但由於每次申請的內存大小不一樣就會產生很多內存碎片,造成不好管理與浪費的情況。
內存池則是在真正使用內存之前,先申請分配一定數量的、大小相等(一般情況下)的內存塊留作備用。當有新的內存需求時,就從內存池中分出一部分內存塊,若內存塊不夠再繼續申請新的內存。這樣做的一個顯著優點是盡量避免了內存碎片,使得內存分配效率得到提升。
進程池&&線程池
這兩個問題有一定的相似度,在面向對象程序編程中,對象的創建與析構都是一個較為復雜的過程,較費時間,所以為了提高程序的運行效率盡可能減少創建和銷毀對象的次數,特別是一些很耗資源的對象創建和銷毀。
所以我們可以創建一個進程池(線程池),預先放一些進程(線程)進去,要用的時候就直接調用,用完之后再把進程歸還給進程池,省下創建刪除進程的時間,不過當然就需要額外的開銷了。
利用線程池與進程池可以使管理進程與線程的工作交給系統管理,不需要程序員對里面的線程、進程進行管理。
線程池主要用於
1、需要大量的線程來完成任務,且完成任務的時間比較短。 WEB服務器完成網頁請求這樣的任務,使用線程池技術是非常合適的。因為單個任務小,而任務數量巨大,你可以想象一個熱門網站的點擊次數。但對於長時間的任務,比如一個Telnet連接請求,線程池的優點就不明顯了。因為Telnet會話時間比線程的創建時間大多了。
2、對性能要求苛刻的應用,比如要求服務器迅速響應客戶請求。
3、接受突發性的大量請求,但不至於使服務器因此產生大量線程的應用。突發性大量客戶請求,在沒有線程池情況下,將產生大量線程,雖然理論上大部分操作系統線程數目最大值不是問題,短時間內產生大量線程可能使內存到達極限,並出現"OutOfMemory"的錯誤。
線程池優點
首先說一下多線程的好處:多線程技術主要解決處理器單元內多個線程執行的問題,它可以顯著減少處理器單元的閑置時間,增加處理器單元的吞吐能力。
我們知道應用程序創建一個對象,然后銷毀對象是很耗費資源的。創建線程,銷毀線程,也是如此。因此,我們就預先生成一些線程,等到我們使用的時候在進行調度,於是,一些"池化資源"技術就這樣的產生了。
本文所提到服務器程序是指能夠接受客戶請求並能處理請求的程序,而不只是指那些接受網絡客戶請求的網絡服務器程序。
多線程技術主要解決處理器單元內多個線程執行的問題,它可以顯著減少處理器單元的閑置時間,增加處理器單元的吞吐能力。但如果對多線程應用不當,會增加對單個任務的處理時間。可以舉一個簡單的例子:
假設在一台服務器完成一項任務的時間為T
T1 創建線程的時間
T2 在線程中執行任務的時間,包括線程間同步所需時間
T3 線程銷毀的時間
顯然T = T1+T2+T3。注意這是一個極度簡化的假設。
可以看出T1,T3是多線程本身的帶來的開銷,我們渴望減少T1,T3所用的時間,從而減少T的時間。但一些線程的使用者並沒有注意到這一點,所以在程序中頻繁的創建或銷毀線程,這導致T1和T3在T中占有相當比例。顯然這是突出了線程的弱點(T1,T3),而不是優點(並發性)。
線程池技術正是關注如何縮短或調整T1,T3時間的技術,從而提高服務器程序性能的。它把T1,T3分別安排在服務器程序的啟動和結束的時間段或者一些空閑的時間段,這樣在服務器程序處理客戶請求時,不會有T1,T3的開銷了。
線程池不僅調整T1,T3產生的時間段,而且它還顯著減少了創建線程的數目。在看一個例子:
假設一個服務器一天要處理50000個請求,並且每個請求需要一個單獨的線程完成。我們比較利用線程池技術和不利於線程池技術的服務器處理這些請求時所產生的線程總數。在線程池中,線程數一般是固定的,所以產生線程總數不會超過線程池中線程的數目或者上限(以下簡稱線程池尺寸),而如果服務器不利用線程池來處理這些請求則線程總數為50000。一般線程池尺寸是遠小於50000。所以利用線程池的服務器程序不會為了創建50000而在處理請求時浪費時間,從而提高效率。
線程池的簡單實現
#ifndef __THREAD_H #define __THREAD_H #include <vector> #include <string> #include <pthread.h> using namespace std; /** * 執行任務的類,設置任務數據並執行 */ class CTask { protected: string m_strTaskName; /** 任務的名稱 */ void* m_ptrData; /** 要執行的任務的具體數據 */ public: CTask(){} CTask(const string& taskName) { m_strTaskName = taskName; m_ptrData = NULL; } virtual ~CTask(){} virtual int Run() = 0; void SetData(void* data); /** 設置任務數據 */ }; /** * 線程池管理類的實現 */ class CThreadPool { private: static vector<CTask*> m_vecTaskList; /** 任務列表 */ static bool shutdown; /** 線程退出標志 */ int m_iThreadNum; /** 線程池中啟動的線程數 */ pthread_t *pthread_id; static pthread_mutex_t m_pthreadMutex; /** 線程同步鎖 */ static pthread_cond_t m_pthreadCond; /** 線程同步的條件變量 */ protected: static void* ThreadFunc(void * threadData); /** 新線程的線程回調函數 */ static int MoveToIdle(pthread_t tid); /** 線程執行結束后,把自己放入到空閑線程中 */ static int MoveToBusy(pthread_t tid); /** 移入到忙碌線程中去 */ int Create(); /** 創建線程池中的線程 */ public: CThreadPool(int threadNum = 10); int AddTask(CTask *task); /** 把任務添加到任務隊列中 */ int StopAll(); /** 使線程池中的線程退出 */ int getTaskSize(); /** 獲取當前任務隊列中的任務數 */ }; #endif
thread.cpp:
#include "Thread.h" #include <iostream> #include "stdlib.h" void CTask::SetData(void * data) { m_ptrData = data; } vector<CTask*> CThreadPool::m_vecTaskList; //任務列表 bool CThreadPool::shutdown = false; pthread_mutex_t CThreadPool::m_pthreadMutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t CThreadPool::m_pthreadCond = PTHREAD_COND_INITIALIZER; /** * 線程池管理類構造函數 */ CThreadPool::CThreadPool(int threadNum) { this->m_iThreadNum = threadNum; cout << "I will create " << threadNum << " threads" << endl; Create(); } /** * 線程回調函數 */ void* CThreadPool::ThreadFunc(void* threadData) { pthread_t tid = pthread_self(); while (1) { pthread_mutex_lock(&m_pthreadMutex); while (m_vecTaskList.size() == 0 && !shutdown) { pthread_cond_wait(&m_pthreadCond, &m_pthreadMutex); } if (shutdown) { pthread_mutex_unlock(&m_pthreadMutex); printf("thread %lu will exit\n", pthread_self()); pthread_exit(NULL); } printf("tid %lu run\n", tid); vector<CTask*>::iterator iter = m_vecTaskList.begin(); /** * 取出一個任務並處理之 */ CTask* task = *iter; if (iter != m_vecTaskList.end()) { task = *iter; m_vecTaskList.erase(iter); } pthread_mutex_unlock(&m_pthreadMutex); task->Run(); /** 執行任務 */ printf("tid:%lu idle\n", tid); } return (void*)0; } /** * 往任務隊列里邊添加任務並發出線程同步信號 */ int CThreadPool::AddTask(CTask *task) { pthread_mutex_lock(&m_pthreadMutex); this->m_vecTaskList.push_back(task); pthread_mutex_unlock(&m_pthreadMutex); pthread_cond_signal(&m_pthreadCond); return 0; } /** * 創建線程 */ int CThreadPool::Create() { pthread_id = (pthread_t*)malloc(sizeof(pthread_t) * m_iThreadNum); for(int i = 0; i < m_iThreadNum; i++) { pthread_create(&pthread_id[i], NULL, ThreadFunc, NULL); } return 0; } /** * 停止所有線程 */ int CThreadPool::StopAll() { /** 避免重復調用 */ if (shutdown) { return -1; } printf("Now I will end all threads!!\n"); /** 喚醒所有等待線程,線程池要銷毀了 */ shutdown = true; pthread_cond_broadcast(&m_pthreadCond); /** 阻塞等待線程退出,否則就成僵屍了 */ for (int i = 0; i < m_iThreadNum; i++) { pthread_join(pthread_id[i], NULL); } free(pthread_id); pthread_id = NULL; /** 銷毀條件變量和互斥體 */ pthread_mutex_destroy(&m_pthreadMutex); pthread_cond_destroy(&m_pthreadCond); return 0; } /** * 獲取當前隊列中任務數 */ int CThreadPool::getTaskSize() { return m_vecTaskList.size(); }
main.cpp:
#include "Thread.h" #include <iostream> #include <unistd.h> #include <stdlib.h> class CMyTask: public CTask { public: CMyTask(){} inline int Run() { printf("%s\n", (char*)this->m_ptrData); sleep(10); return 0; } }; int main() { CMyTask taskObj; char szTmp[] = "this is the new thread running"; taskObj.SetData((void*)szTmp); CThreadPool threadPool(10); for(int i = 0; i < 20; i++) { threadPool.AddTask(&taskObj); } while(1) { printf("there are still %d tasks need to handle\n", threadPool.getTaskSize()); if (threadPool.getTaskSize() == 0) { if (threadPool.StopAll() == -1) { printf("Now I will exit from main\n"); exit(0); } } sleep(2); } return 0; }