Linux:實現一個簡單的線程池

線程池

一、定義:線程池是一種線程使用模式。

二、目的:線程過多會帶來調度開銷,進而影響緩存局部性和整體性能。而線程池維護着多個線程,等待着監督管理者分配可併發執行的任務。這避免了在處理短時間任務時創建與銷燬線程的代價。線程池不僅能夠保證內核的充分利用,還能防止過分調度。可用線程數量應該取決於可用的併發處理器、處理器內核、內存、網絡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 
  • 運行之:

  • 運行步驟:

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