Linux線程池的設計

我設計這個線程池的初衷是為了與socket對接的。線程池的實現千變萬化,我得這個并不一定是最好的,但卻是否和我心目中需求模型的。現把部分設計思路和代碼貼出,以期拋磚引玉。個人比較喜歡搞開源,所以大家如果覺得有什么需要改善的地方,歡迎給予評論。思前想后,也沒啥設計圖能表達出設計思想,就把類圖貼出來吧。

類圖設計如下:

Command類是我們的業務類。這個類里只能存放簡單的內置類型,這樣方便與socket的直接傳輸。我定義了一個cmd_成員用于存放命令字,arg_用于存放業務的參數。這個參數可以使用分隔符來分隔各個參數。我設計的只是簡單實現,如果有序列化操作了,完全不需要使用我這種方法啦。

ThreadProcess就是業務處理類,這里邊定義了各個方法用于進行業務處理,它將在ThreadPool中的Process函數中調用。

ThreadPool就是我們的線程池類。其中的成員變量都是靜態變量,Process就是線程處理函數。

#define MAX_THREAD_NUM 50 // 該值目前需要設定為初始線程數的整數倍
#define ADD_FACTOR 40 // 該值表示一個線程可以處理的最大任務數
#define THREAD_NUM 10 // 初始線程數

bshutdown_:用于線程退出。

command_:用于存放任務隊列

command_cond_:條件變量

command_mutex_:互斥鎖

icurr_thread_num_:當前線程池中的線程數

thread_id_map_:這個map用于存放線程對應的其它信息,我只存放了線程的狀態,0為正常,1為退出。還可以定義其它的結構來存放更多的信息,例如存放套接字。

InitializeThreads:用于初始化線程池,先創建THREAD_NUM個線程。后期擴容也需要這個函數。

Process:線程處理函數,這里邊會調用AddThread和DeleteThread在進行線程池的伸縮。

AddWork:往隊列中添加一個任務。

ThreadDestroy:線程銷毀函數。

AddThread:擴容THREAD_NUM個線程

DeleteThread:如果任務隊列為空,則將原來的線程池恢復到THREAD_NUM個。這里可以根據需要進行修改。

?

以下貼出代碼以供大家參考。

command.h

復制代碼
#ifndef COMMAND_H_
#define COMMAND_H_class Command
{
public:int get_cmd();char* get_arg();void set_cmd(int cmd);void set_arg(char* arg);
private:int cmd_;char arg_[65];
};#endif /* COMMAND_H_ */
復制代碼

command.cpp

復制代碼
#include <string.h>
#include "command.h"int Command::get_cmd()
{return cmd_;
}char* Command::get_arg()
{return arg_;
}void Command::set_cmd(int cmd)
{cmd_ = cmd;
}void Command::set_arg(char* arg)
{if(NULL == arg){return;}strncpy(arg_,arg,64);arg_[64] = '\0';
}
復制代碼

thread_process.h

復制代碼
#ifndef THREAD_PROCESS_H_
#define THREAD_PROCESS_H_class ThreadProcess
{
public:void Process0(void* arg);void Process1(void* arg);void Process2(void* arg);
};#endif /* THREAD_PROCESS_H_ */
復制代碼

thread_process.cpp

復制代碼
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include "thread_process.h"void ThreadProcess::Process0(void* arg)
{printf("thread %u is starting process %s\n",pthread_self(),arg);usleep(100*1000);
}
void ThreadProcess::Process1(void* arg)
{printf("thread %u is starting process %s\n",pthread_self(),arg);usleep(100*1000);
}void ThreadProcess::Process2(void* arg)
{printf("thread %u is starting process %s\n",pthread_self(),arg);usleep(100*1000);
}
復制代碼

thread_pool.h

復制代碼
#ifndef THREAD_POOL_H_
#define THREAD_POOL_H_#include <map>
#include <vector>
#include "command.h"#define MAX_THREAD_NUM 50 // 該值目前需要設定為初始線程數的整數倍
#define ADD_FACTOR 40 // 該值表示一個線程可以處理的最大任務數
#define THREAD_NUM 10 // 初始線程數class ThreadPool
{
public:ThreadPool() {};static void InitializeThreads();void AddWork(Command command);void ThreadDestroy(int iwait = 2);
private:static void* Process(void* arg);static void AddThread();static void DeleteThread();static bool bshutdown_;static int icurr_thread_num_;static std::map<pthread_t,int> thread_id_map_;static std::vector<Command> command_;static pthread_mutex_t command_mutex_;static pthread_cond_t command_cond_;
};#endif /* THREAD_POOL_H_ */
復制代碼

thread_pool.cpp

復制代碼
#include <pthread.h>
#include <stdlib.h>
#include "thread_pool.h"
#include "thread_process.h"
#include "command.h"bool ThreadPool::bshutdown_ = false;
int ThreadPool::icurr_thread_num_ = THREAD_NUM;
std::vector<Command> ThreadPool::command_;
std::map<pthread_t,int> ThreadPool::thread_id_map_;
pthread_mutex_t ThreadPool::command_mutex_ = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t ThreadPool::command_cond_ = PTHREAD_COND_INITIALIZER;void ThreadPool::InitializeThreads()
{for (int i = 0; i < THREAD_NUM ; ++i){pthread_t tempThread;pthread_create(&tempThread, NULL, ThreadPool::Process, NULL);thread_id_map_[tempThread] = 0;}
}void* ThreadPool::Process(void* arg)
{ThreadProcess threadprocess;Command command;while (true){pthread_mutex_lock(&command_mutex_);// 如果線程需要退出,則此時退出if (1 == thread_id_map_[pthread_self()]){pthread_mutex_unlock(&command_mutex_);printf("thread %u will exit\n", pthread_self());pthread_exit(NULL);}// 當線程不需要退出且沒有需要處理的任務時,需要縮容的則縮容,不需要的則等待信號if (0 == command_.size() && !bshutdown_){if(MAX_THREAD_NUM != THREAD_NUM){DeleteThread();if (1 == thread_id_map_[pthread_self()]){pthread_mutex_unlock(&command_mutex_);printf("thread %u will exit\n", pthread_self());pthread_exit(NULL);}}pthread_cond_wait(&command_cond_,&command_mutex_);}// 線程池需要關閉,關閉已有的鎖,線程退出if(bshutdown_){pthread_mutex_unlock (&command_mutex_);printf ("thread %u will exit\n", pthread_self ());pthread_exit (NULL);}// 如果線程池的最大線程數不等于初始線程數,則表明需要擴容if(MAX_THREAD_NUM != THREAD_NUM){AddThread();}// 從容器中取出待辦任務std::vector<Command>::iterator iter = command_.begin();command.set_arg(iter->get_arg());command.set_cmd(iter->get_cmd());command_.erase(iter);pthread_mutex_unlock(&command_mutex_);// 開始業務處理switch(command.get_cmd()){case 0:threadprocess.Process0(command.get_arg());break;case 1:threadprocess.Process1(command.get_arg());break;case 2:threadprocess.Process2(command.get_arg());break;default:break;}}return NULL; // 完全為了消除警告(eclipse編寫的代碼,警告很煩人)
}void ThreadPool::AddWork(Command command)
{bool bsignal = false;pthread_mutex_lock(&command_mutex_);if (0 == command_.size()){bsignal = true;}command_.push_back(command);pthread_mutex_unlock(&command_mutex_);if (bsignal){pthread_cond_signal(&command_cond_);}
}void ThreadPool::ThreadDestroy(int iwait)
{while(0 != command_.size()){sleep(abs(iwait));}bshutdown_ = true;pthread_cond_broadcast(&command_cond_);std::map<pthread_t,int>::iterator iter = thread_id_map_.begin();for (; iter!=thread_id_map_.end(); ++iter){pthread_join(iter->first,NULL);}pthread_mutex_destroy(&command_mutex_);pthread_cond_destroy(&command_cond_);
}void ThreadPool::AddThread()
{if(((icurr_thread_num_*ADD_FACTOR) < command_.size())&& (MAX_THREAD_NUM != icurr_thread_num_)){InitializeThreads();icurr_thread_num_ += THREAD_NUM;}
}void ThreadPool::DeleteThread()
{int size = icurr_thread_num_ - THREAD_NUM;std::map<pthread_t,int>::iterator iter = thread_id_map_.begin();for(int i=0; i<size; ++i,++iter){iter->second = 1;}
}
復制代碼

main.cpp

復制代碼
#include "thread_pool.h"
#include "command.h"int main()
{ThreadPool thread_pool;thread_pool.InitializeThreads();Command command;char arg[8] = {0};for(int i=1; i<=1000; ++i){command.set_cmd(i%3);sprintf(arg,"%d",i);command.set_arg(arg);thread_pool.AddWork(command);}sleep(10); // 用于測試線程池縮容
    thread_pool.ThreadDestroy();return 0;
}
復制代碼

?

代碼是按照google的開源c++編碼規范編寫。大家可以通過改變那幾個宏的值來調整線程池。有問題大家一起討論。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/445040.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/445040.shtml
英文地址,請注明出處:http://en.pswp.cn/news/445040.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

算法(12)-leetcode-explore-learn-數據結構-雙鏈表的設計

leetcode-explore-learn-數據結構-鏈表4雙鏈表的設計本系列博文為leetcode-explore-learn子欄目學習筆記&#xff0c;如有不詳之處&#xff0c;請參考leetcode官網&#xff1a;https://leetcode-cn.com/explore/learn/card/linked-list/所有例題的編程語言為python 雙鏈表的設…

安全方面知識

什么是文件上傳漏洞 文件上傳漏洞是指 由于程序員在對用戶文件上傳部分的控制不足或者處理缺陷&#xff0c;而導致的用戶可以越過其本身權限向服務器上上傳可執行的動態腳本文件 這里上傳的文件可以是木馬&#xff0c;病毒&#xff0c;惡意腳本或者WebShell等。 這種攻擊方式是…

CE游戲外掛工具

CHEAT ENGINE(以下簡稱CE)是我見過的最優秀的游戲作弊工具。它的優點多不勝數&#xff0c;雖然單獨從搜索游 戲里面的數值來說&#xff0c;它并不比其他同類軟件強多少&#xff0c;但它不僅僅是個游戲修改工具&#xff0c;它還有其他游戲修改軟件所沒有的一些特點&#xff0c;例…

外掛編程-動作模擬技術

幾乎所有的游戲都有大量繁瑣和無聊的攻擊動作以增加玩家的 功力,還有那些數不完的迷宮,這些好像已經成為了角色游戲的代名詞。現在,外掛可以幫助玩家從這些繁瑣而無聊 的工作中擺脫出來。 1. 鼠標模擬技術 幾乎所有的游戲中都使用了鼠標來改變角色的位置和方向,玩家僅用…

算法(13)-leetcode-explore-learn-數據結構-鏈表小結

leetcode-explore-learn-數據結構-鏈表51.小結2.例題2.1合并兩個有序鏈表思路1:迭代思路2:遞歸2.2 兩數相加2.3 扁平化多級雙向鏈表2.4 復制帶隨機指針的鏈表2.5 旋轉鏈表本系列博文為leetcode-explore-learn子欄目學習筆記&#xff0c;如有不詳之處&#xff0c;請參考leetcode…

leetcode121買賣股票的最佳時機

給定一個數組&#xff0c;它的第 i 個元素是一支給定股票第 i 天的價格。 如果你最多只允許完成一筆交易&#xff08;即買入和賣出一支股票&#xff09;&#xff0c;設計一個算法來計算你所能獲取的最大利潤。 注意你不能在買入股票前賣出股票。 示例 1: 輸入: [7,1,5,3,6,…

epoll的內核實現

epoll是由一組系統調用組成。 int epoll_create(int size); int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout); select/poll的缺點在于&#xff1…

算法(14)-數據結構-二叉樹

leetcode-explore-learn-數據結構-二叉樹10.概述1.深度優先遍歷dfs1.1先序遍歷-中左右1.2中序遍歷-左中右1.3后序遍歷-左右中2.廣度優先遍歷bfs3.遍歷-常見問題3.1 二叉樹的最大深度自頂向下自底向上3.2對稱二叉樹3.3路徑總和4.重構-常見問題4.1根據中序和后序遍歷序列構造二叉…

多進程魚多線程的權衡選擇

最近有好多人在網上問道做游戲開發框架用多線程還是多進程呢,或者兩者之間的優缺點,等等類似的問題。下邊小高就帶您小小分析一下: 1、首先要明確進程和線程的含義:進程(Process)是具有一定獨立功能的程序關于某個數據集合上的一次運行活動,是系統進行資源分配和調度的一…

leetcode322 零錢兌換

給定不同面額的硬幣 coins 和一個總金額 amount。編寫一個函數來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額&#xff0c;返回 -1。 示例 1: 輸入: coins [1, 2, 5], amount 11 輸出: 3 解釋: 11 5 5 1 示例 2: 輸入: coins [2],…

給數據減肥 讓MySQL數據庫跑的更快

在數據庫優化工作中&#xff0c;使數據盡可能的小&#xff0c;使表在硬盤上占據的空間盡可能的小&#xff0c;這是最常用、也是最有效的手段之一。因為縮小數據&#xff0c;相對來說可以提高硬盤的讀寫速度&#xff0c;并且在查詢過程中小表的內容處理時所占用的系統資源比較少…

算法(15)-leetcode-explore-learn-數據結構-運用遞歸解決二叉樹的問題

leetcode-explore-learn-數據結構-二叉樹2本系列博文為leetcode-explore-learn子欄目學習筆記&#xff0c;如有不詳之處&#xff0c;請參考leetcode官網&#xff1a;https://leetcode-cn.com/explore/learn/card/data-structure-binary-tree/2/traverse-a-tree/7/

leetcode538 把二叉搜索樹轉換成累加樹

給定一個二叉搜索樹&#xff08;Binary Search Tree&#xff09;&#xff0c;把它轉換成為累加樹&#xff08;Greater Tree)&#xff0c;使得每個節點的值是原來的節點值加上所有大于它的節點值之和。 對于每一個點來說&#xff0c;自己的父&#xff0c;和自己父的右子樹都是大…

AWK常用命令華(1)

awk 調用: 1.調用awk:

AWk的調用精華

awk 的調用方式 awk 提供了適應多種需要的不同解決方案,它們是: 一、awk 命令行,你可以象使用普通UNIX 命令一樣使用awk,在命令行中你也可以使用awk 程序設計語言,雖然awk 支持多行的錄入,但是錄入長長的命令行并保證其正 確無誤卻是一件令人頭疼的事,因此,這種方法一般…

算法(16)-leetcode-explore-learn-數據結構-二叉樹總結

leetcode-explore-learn-數據結構-二叉樹3本系列博文為leetcode-explore-learn子欄目學習筆記&#xff0c;如有不詳之處&#xff0c;請參考leetcode官網&#xff1a;https://leetcode-cn.com/explore/learn/card/data-structure-binary-tree/2/traverse-a-tree/7/所有例題的編程…

leetcode15 三數之和

給定一個包含 n 個整數的數組 nums&#xff0c;判斷 nums 中是否存在三個元素 a&#xff0c;b&#xff0c;c &#xff0c;使得 a b c 0 &#xff1f;找出所有滿足條件且不重復的三元組。 注意&#xff1a;答案中不可以包含重復的三元組。 例如, 給定數組 nums [-1, 0, 1,…

AWK再次認識--內置的參數,以及編寫腳本

原本這是篇給公司內同事寫的培訓文章&#xff0c;對于初學awk的人還蠻有幫助&#xff0c;貼到這里與大家共享一下。 〇、前言 意見反饋&#xff0c;請mailto:datouwanggmail.com。 一、AWK簡介 AWK名字來源于三位創造者Aho、Weinberger和Kernighan統稱。 AWK擅長處理文本數據。…

AWk高級編程

首先再說一說awk的工作流程還是有必要的 : 執行awk時, 它會反復進行下列四步驟. 1. 自動從指定的數據文件中讀取一個數據行. 2. 自動更新(Update)相關的內建變量之值. 如 : NF, NR, $0... 3. 依次執行程序中所有 的 Pattern { Actions } 指令. 4. 當執行完程序中所有 Pattern {…

leetcode19. 刪除鏈表的倒數第N個節點

給定一個鏈表&#xff0c;刪除鏈表的倒數第 n 個節點&#xff0c;并且返回鏈表的頭結點。 示例&#xff1a; 給定一個鏈表: 1->2->3->4->5, 和 n 2. 當刪除了倒數第二個節點后&#xff0c;鏈表變為 1->2->3->5. 說明&#xff1a; 給定的 n 保證是有效…