線程池的簡單實現
文章目錄
一 線程池的定義
線程池就是有一堆已經創建好了的線程,初始都處於空閒等待狀態,當有新的任務需要處理的時候,就從這堆線程(線程池)中取一個空閒等待的線程來處理任務,當任務處理完畢後,就再次把該線程放回池中(一般就是將線程狀態置爲空閒),以供後面的任務繼續使用。當池子裏的線程全都處於忙碌狀態時,線程池中沒有可用的空閒等待線程,此時根據需要選擇創建一個新的線程並置入池中,或者通知任務當前線程池裏所有線程都在忙,等待片刻再嘗試。
二 使用線程池的原因
線程池的好處就在於線程複用。某個線程在處理完一個任務後,可以繼續處理下一個任務,而不用銷燬後再創建,這樣可以避免無謂的開銷,因此尤其適用於連續產生大量併發任務的場合。
三 用C++實現一個簡單的線程池
3.1 thread_pool.h
#ifndef LINUXPRO_THREAD_POOL_H
#include <vector>
#include <string>
#include <pthread.h>
using namespace std;
/*執行任務的類:設置任務數據並執行*/
class Task
{
protected:
string m_taskName;
void *m_data; // 任務數據
public:
Task() = default;
Task(string &taskName) : m_taskName(taskName), m_data(NULL) {}
virtual int Run() = 0;
void SetData(void *data); // 設置任務數據
virtual ~Task() {}
};
/*線程池管理類*/
class ThreadPool
{
private:
static vector<Task *> m_taskList; // 任務列表
static bool m_shutDown; // 線程退出標誌
int m_threadNum; // 線程池中啓動的線程數
pthread_t *m_pthreadId;
static pthread_mutex_t m_pthreadMutex; // 線程同步鎖
static pthread_cond_t m_pthreadCond; // 線程同步條件變量
protected:
static void* ThreadFun(void *threadData); // 新線程的線程回調函數
static int MoveToIdle(pthread_t threadId); // 線程執行結束後,把自己放入空閒線程中
static int MoveToBusy(pthread_t threadId); // 移入線程到忙碌線程中
int Create(); // 創建線程池中的線程
public:
ThreadPool(int threadNum);
int AddTask(Task *task); // 把任務添加到任務隊列中
int StopAll(); // 使線程池中的所有線程退出
int GetTaskSize(); // 獲取當前任務隊列中的任務數
};
#define LINUXPRO_THREAD_POOL_H
#endif //LINUXPRO_THREAD_POOL_H
3.2 thread_pool.cpp
#include <cstdio>
#include "thread_pool.h"
void Task::SetData(void *data)
{
m_data = data;
}
// 靜態成員初始化
vector<Task *> ThreadPool::m_taskList;
bool ThreadPool::m_shutDown = false;
pthread_mutex_t ThreadPool::m_pthreadMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t ThreadPool::m_pthreadCond = PTHREAD_COND_INITIALIZER;
// 線程池構造函數
ThreadPool::ThreadPool(int threadNum)
{
this->m_threadNum = threadNum;
printf("it will create %d threads.\n", threadNum);
Create();
}
// 線程回調函數
void* ThreadPool::ThreadFun(void *threadData)
{
pthread_t threadId = pthread_self();
while (1)
{
pthread_mutex_lock(&m_pthreadMutex);
// 如果隊列爲空,等待新的任務進入隊列
while (0 == m_taskList.size() && !m_shutDown)
{
pthread_cond_wait(&m_pthreadCond, &m_pthreadMutex);
}
// 關閉線程
if (m_shutDown)
{
pthread_mutex_unlock(&m_pthreadMutex);
printf("[threadId:%lu]\texit\n", pthread_self());
pthread_exit(NULL);
}
printf("[threadId:%lu]\tturn:\n", threadId);
vector<Task *>::iterator iter = m_taskList.begin();
// 取出一個任務並處理
Task *task = *iter;
if (m_taskList.end() != iter)
{
task = *iter;
m_taskList.erase(iter);
}
pthread_mutex_unlock(&m_pthreadMutex);
task->Run(); // 執行任務
printf("[threadId:%lu]\tidle:\n", threadId);
}
return (void *)0;
}
// 往任務隊列裏添加併發出線程同步信號
int ThreadPool::AddTask(Task *task)
{
pthread_mutex_lock(&m_pthreadMutex);
m_taskList.push_back(task);
pthread_mutex_unlock(&m_pthreadMutex);
pthread_cond_signal(&m_pthreadCond);
return 0;
}
// 創建線程
int ThreadPool::Create()
{
m_pthreadId = new pthread_t[m_threadNum];
for (int i = 0; i < m_threadNum; i++)
{
pthread_create(&m_pthreadId[i], NULL, ThreadFun, NULL);
}
return 0;
}
// 停止所有線程
int ThreadPool::StopAll()
{
// 避免重複
if (m_shutDown)
{
return -1;
}
printf("Now it will end all threads!\n\n");
// 喚醒所有等待線程,線程池也要銷燬了
m_shutDown = true;
pthread_cond_broadcast(&m_pthreadCond);
for (int i = 0; i < m_threadNum; i++)
{
pthread_join(m_pthreadId[i], NULL);
}
// 清理殭屍線程
delete[](m_pthreadId);
m_pthreadId = NULL;
// 銷燬互斥鎖和條件變量
pthread_mutex_destroy(&m_pthreadMutex);
pthread_cond_destroy(&m_pthreadCond);
return 0;
}
// 獲取當前任務隊列中的任務數
int ThreadPool::GetTaskSize()
{
return m_taskList.size();
}
3.3 thread_pool_use.cpp
#include <cstdio>
#include <stdlib.h>
#include <unistd.h>
#include "thread_pool.h"
class MyTask : public Task
{
public:
MyTask() = default;
int Run()
{
printf("%s\n", (char *)m_data);
sleep(1);
return 0;
}
~MyTask() {}
};
int main()
{
MyTask taskObj;
char str[] = "hello!";
taskObj.SetData((void *)str);
ThreadPool threadPool(5); // 線程池大小爲5
for (int i = 0; i < 10; i++)
{
threadPool.AddTask(&taskObj);
}
while (1)
{
printf("There are still %d tasks need to handle\n", threadPool.GetTaskSize());
// 任務隊列已經沒有任務了
if (0 == threadPool.GetTaskSize())
{
// 清除線程池
if (-1 == threadPool.StopAll())
{
printf("Thread pool clear, eixt.\n");
exit(0);
}
}
sleep(2);
printf("2 seconds later...\n");
}
return 0;
}
3.4 編譯生成 test 可執行程序
g++ thread_pool.cpp thread_pool_use.cpp -o test -lpthread -std=c++11
3.5 輸出結果
it will create 5 threads.
There are still 10 tasks need to handle
[threadId:140571464595200] turn:
hello!
[threadId:140571456202496] turn:
hello!
[threadId:140571489773312] turn:
hello!
[threadId:140571481380608] turn:
hello!
[threadId:140571472987904] turn:
hello!
[threadId:140571489773312] idle:
[threadId:140571489773312] turn:
hello!
[threadId:140571472987904] idle:
[threadId:140571472987904] turn:
hello!
[threadId:140571456202496] idle:
[threadId:140571456202496] turn:
hello!
[threadId:140571481380608] idle:
[threadId:140571481380608] turn:
hello!
[threadId:140571464595200] idle:
[threadId:140571464595200] turn:
hello!
2 seconds later...
There are still 0 tasks need to handle
Now it will end all threads!
[threadId:140571489773312] idle:
[threadId:140571489773312] exit
[threadId:140571472987904] idle:
[threadId:140571472987904] exit
[threadId:140571456202496] idle:
[threadId:140571456202496] exit
[threadId:140571481380608] idle:
[threadId:140571481380608] exit
[threadId:140571464595200] idle:
[threadId:140571464595200] exit
2 seconds later...
There are still 0 tasks need to handle
Thread pool clear, eixt.