介紹及線程池,C++實現內存池、進程池、線程池

 

內存池

平常我們使用new、malloc在堆區申請一塊內存,但由於每次申請的內存大小不一樣就會產生很多內存碎片,造成不好管理與浪費的情況。

內存池則是在真正使用內存之前,先申請分配一定數量的、大小相等(一般情況下)的內存塊留作備用。當有新的內存需求時,就從內存池中分出一部分內存塊,若內存塊不夠再繼續申請新的內存。這樣做的一個顯著優點是儘量避免了內存碎片,使得內存分配效率得到提升。

進程池&&線程池

這兩個問題有一定的相似度,在面向對象程序編程中,對象的創建與析構都是一個較爲複雜的過程,較費時間,所以爲了提高程序的運行效率儘可能減少創建和銷燬對象的次數,特別是一些很耗資源的對象創建和銷燬。

所以我們可以創建一個進程池(線程池),預先放一些進程(線程)進去,要用的時候就直接調用,用完之後再把進程歸還給進程池,省下創建刪除進程的時間,不過當然就需要額外的開銷了。

利用線程池與進程池可以使管理進程與線程的工作交給系統管理,不需要程序員對裏面的線程、進程進行管理。

需要c/c++ Linux服務器高階知識視頻資料的朋友可以點擊鏈接加入羣聊【linux後臺服務架構交流】

 

 

線程池主要用於

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;
}

運行結果

I will create 10 threads

tid 4378075136 run

this is the new thread running

tid 4373245952 run

this is the new thread running

tid 4373782528 run

this is the new thread running

tid 4374855680 run

this is the new thread running

tid 4374319104 run

this is the new thread running

tid 4375392256 run

this is the new thread running

tid 4375928832 run

this is the new thread running

tid 4376465408 run

this is the new thread running

tid 4377001984 run

this is the new thread running

tid 4377538560 run

this is the new thread running

there are still 10 tasks need to handle

there are still 10 tasks need to handle

there are still 10 tasks need to handle

there are still 10 tasks need to handle

there are still 10 tasks need to handle

tid:4373782528 idle

tid:4375928832 idle

tid:4375392256 idle

tid:4376465408 idle

tid:4374319104 idle

tid:4373245952 idle

tid:4377001984 idle

tid:4378075136 idle

tid:4374855680 idle

tid 4373782528 run

tid:4377538560 idle

this is the new thread running

tid 4375928832 run

this is the new thread running

tid 4375392256 run

this is the new thread running

tid 4376465408 run

this is the new thread running

tid 4374319104 run

this is the new thread running

tid 4373245952 run

this is the new thread running

tid 4377001984 run

this is the new thread running

tid 4378075136 run

this is the new thread running

tid 4374855680 run

tid 4377538560 run

this is the new thread running

this is the new thread running

there are still 0 tasks need to handle

Now I will end all threads!!

tid:4375928832 idle

tid:4376465408 idle

tid:4375392256 idle

tid:4374319104 idle

tid:4373245952 idle

tid:4377538560 idle

tid:4377001984 idle

tid:4378075136 idle

tid:4373782528 idle

tid:4374855680 idle

thread 4375928832 will exit

thread 4376465408 will exit

thread 4375392256 will exit

thread 4374319104 will exit

thread 4373245952 will exit

thread 4377538560 will exit

thread 4377001984 will exit

thread 4378075136 will exit

thread 4373782528 will exit

thread 4374855680 will exit

there are still 0 tasks need to handle

Now I will exit from main

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章