13 —— 線程池的簡單實現

線程池的簡單實現


一 線程池的定義

  線程池就是有一堆已經創建好了的線程,初始都處於空閒等待狀態,當有新的任務需要處理的時候,就從這堆線程(線程池)中取一個空閒等待的線程來處理任務,當任務處理完畢後,就再次把該線程放回池中(一般就是將線程狀態置爲空閒),以供後面的任務繼續使用。當池子裏的線程全都處於忙碌狀態時,線程池中沒有可用的空閒等待線程,此時根據需要選擇創建一個新的線程並置入池中,或者通知任務當前線程池裏所有線程都在忙,等待片刻再嘗試。

二 使用線程池的原因

  線程池的好處就在於線程複用。某個線程在處理完一個任務後,可以繼續處理下一個任務,而不用銷燬後再創建,這樣可以避免無謂的開銷,因此尤其適用於連續產生大量併發任務的場合。

三 用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.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章