【Linux】スレッド----スレッドプール


スレッドプール
  • スレッドプール
  • を使用する理由
  • スレッドプール原理
  • 構想
  • コード実装
  • 注意事項

  • スレッドプールを使用する理由
  • スレッドが多すぎると、スケジューリングオーバーヘッドが発生し、キャッシュのローカル性と全体的なパフォーマンスに影響します.スレッドプールは複数のスレッドを維持し、監督管理者が同時実行可能なタスクを割り当てるのを待っています.これにより、短時間のタスクを処理する際にスレッドを作成および破棄するコストが回避されます.スレッドプールは、カーネルの十分な利用を保証するだけでなく、過度なスケジューリングを防止します.

  • スレッドプールの原理
  • サーバが起動すると、 + をスレッドプールとして作成し、タスクが来たら、タスクをスレッドプールのタスクキューに投げ込み、スレッドプールの1つのスレッドがタスクキューにループしてタスクを取得して処理
  • を行う.
  • スレッドプールの実装:大量のスレッド+スレッドセキュリティのタスクキュー
  • 構想
  • タスククラスを介してスレッドプールへのタスクの投げ込みを実現する場合、
  • も投げ込む.
  • スレッドプール内のスレッドは、タスクオブジェクトを取得する後にRunインタフェースを呼び出すだけでタスク処理
  • を実現することができる.
  • スレッドプールは でよい、タスクの処理はすべてオンラインスレッドプール内部で完了した
  • である.
    コード実装
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define THREAD_COUNT 5
    
    typedef void (*task_handler_t) (int arg);
    
    class ThreadTask{
         
      private:
        int _data; //       
        task_handler_t _handler; //        
      public:
        ThreadTask(){
         }
        ThreadTask(const int &data, task_handler_t handler):
        _data(data), _handler(handler){
         }
        void SetTask(const int &data, task_handler_t handler){
         
          _data = data;
          _handler = handler;
        }
        void Run(){
         
          return _handler(_data);
        }
    };
    
    class ThreadPool{
         
      private:
        int _thr_max; //       
        std::queue<ThreadTask> _queue;
        //        ,          ,                     
        //              ,      ,          Run  
        pthread_mutex_t _mutex; //            
        pthread_cond_t _cond_pool; //             ,        
      public:
        ThreadPool(int thr_count = THREAD_COUNT):_thr_max(thr_count){
         
          pthread_mutex_init(&_mutex, NULL);
          pthread_cond_init(&_cond_pool, NULL);
          for(int i = 0; i < _thr_max; ++i){
         
            pthread_t tid;
            int ret = pthread_create(&tid, NULL, thread_routine, (void*)this);
            if(ret != 0){
         
              std::cerr << "thread create error!
    "
    << std::endl; exit(0); } pthread_detach(tid); // -- } } ~ThreadPool(){ pthread_mutex_destroy(&_mutex); pthread_cond_destroy(&_cond_pool); } bool TaskPush(const ThreadTask &task){ pthread_mutex_lock(&_mutex); _queue.push(task); pthread_mutex_unlock(&_mutex); pthread_cond_signal(&_cond_pool); // return true; } void QueueLock(){ pthread_mutex_lock(&_mutex); } bool QueueIsEmpty(){ return _queue.empty(); } void ThreadWait(){ pthread_cond_wait(&_cond_pool, &_mutex); } bool TaskPop(ThreadTask *task){ *task = _queue.front(); _queue.pop(); return true; } void QueueUnlock(){ pthread_mutex_unlock(&_mutex); } private: // , this , // , this , // this , static void *thread_routine(void *arg){ ThreadPool *pool = (ThreadPool*)arg; // while(1){ pool->QueueLock(); while(pool->QueueIsEmpty()){ pool->ThreadWait(); } ThreadTask task; pool->TaskPop(&task); pool->QueueUnlock(); // task.Run(); // Run } return NULL; } }; void test(int data) { srand(time(NULL)); int sec = rand() % 5; printf("thread : %p : %d sleep %d sec
    "
    , pthread_self(), data, sec); sleep(sec); } int main() { ThreadPool pool; for(int i = 0; i < 10; i++){ ThreadTask task; task.SetTask(i, test); pool.TaskPush(task); } while(1){ sleep(1); } return 0; }

    注意事項
  • スレッド作成関数pthread_createは、入力されたエントリ関数にパラメータvoid(*thread_routine)(void*arg)が1つしかないことを要求する.しかし、エントリ関数がクラスのメンバー関数である場合、デフォルトでは非表示パラメータthisポインタが関数パラメータタイプを一致させません.したがって、この をクラス内
  • に配置する必要がある.
  • 静的関数はクラスのメンバーに直接アクセスできないため、このオブジェクトのthisポインタをスレッドエントリ関数を介して入力し、スレッド内部でこのオブジェクトにアクセスできます.ただし、クラス外ではオブジェクトに直接アクセスできないプライベートメンバーを使用するため、
  • を実装するには が必要である.