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.mzph.cn/news/445040.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

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…

leetcode322 零钱兑换

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额&#xff0c;返回 -1。 示例 1: 输入: coins [1, 2, 5], amount 11 输出: 3 解释: 11 5 5 1 示例 2: 输入: coins [2],…

leetcode538 把二叉搜索树转换成累加树

给定一个二叉搜索树&#xff08;Binary Search Tree&#xff09;&#xff0c;把它转换成为累加树&#xff08;Greater Tree)&#xff0c;使得每个节点的值是原来的节点值加上所有大于它的节点值之和。 对于每一个点来说&#xff0c;自己的父&#xff0c;和自己父的右子树都是大…

leetcode15 三数之和

给定一个包含 n 个整数的数组 nums&#xff0c;判断 nums 中是否存在三个元素 a&#xff0c;b&#xff0c;c &#xff0c;使得 a b c 0 &#xff1f;找出所有满足条件且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元组。 例如, 给定数组 nums [-1, 0, 1,…

leetcode19. 删除链表的倒数第N个节点

给定一个链表&#xff0c;删除链表的倒数第 n 个节点&#xff0c;并且返回链表的头结点。 示例&#xff1a; 给定一个链表: 1->2->3->4->5, 和 n 2. 当删除了倒数第二个节点后&#xff0c;链表变为 1->2->3->5. 说明&#xff1a; 给定的 n 保证是有效…

python模块(5)-Matplotlib 简易使用教程

Matplotlib简易使用教程0.matplotlib的安装1.导入相关库2.画布初始化2.1 隐式创建2.2 显示创建2.3 设置画布大小2.4 plt.figure()常用参数3.plt. 能够绘制图像类型3.1等高线3.2 箭头arrow4.简单绘制小demodemo1.曲线图demo2-柱状、饼状、曲线子图5.plt.plot()--设置曲线颜色,粗…

leetcode20 有效的括号

给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串&#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 注意空字符串可被认为是有效字符串。 示…

leetcode1 两数之和

给定一个整数数组 nums 和一个目标值 target&#xff0c;请你在该数组中找出和为目标值的那 两个 整数&#xff0c;并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;你不能重复利用这个数组中同样的元素。 示例: 给定 nums [2, 7, 11, 15], t…

leetcode3 无重复字符最长子串

给定一个字符串&#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所以其长度为 3。 示例 2: 输入: "bbbbb" 输出: 1 解释: 因为无重复字符…

Linux(6)-命令行的使用,history,shell脚本

命令行的使用,shell脚本1.终端shell,man1.1 Ctrlr--匹配查找历史命令1.2 history [n] --列出历史命令1.3&#xff01;--执行历史命令2.shell 编程2.1 shell脚本2.2 注释2.3 指明所用的shell2.4 支持函数2.5 使用变量2.6 解析命令行参数2.7 if, for, case, while2.8 shell脚本中…

程序以及论文

本人长期承接大学计算机专业的毕业设计和论文的编写。 主要开发语言C&#xff0c;C &#xff08;windows或linux平台皆可&#xff09;&#xff0c;php&#xff0c;c#&#xff0c;VC 。 课题内容可以是 管理系统&#xff0c;可以是 网站设计开发 可以是 网络聊天 可以是 应用…

Github(1)-概览,初始化仓库

Github网页-本地git1.github网页1.1 主要界面1.1.1github主页1.1.2仓库主页1.1.3 个人页面1.2 注册github账号1.3 新建平台仓库2.git-本地仓库2.1 git本地仓库的三个区域2.2 创建一个本地仓库GitHub 本质上是一个代码托管平台&#xff0c;它提供的是基于 Git 的代码托管服务。G…

leetcode16 最接近的三数之和

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数&#xff0c;使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。 例如&#xff0c;给定数组 nums [-1&#xff0c;2&#xff0c;1&#xff0c;-4], 和 target 1…

leecode11 盛水最多的容器

给定 n 个非负整数 a1&#xff0c;a2&#xff0c;...&#xff0c;an&#xff0c;每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线&#xff0c;垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多…

leecode26 删除排序数组中的重复项

给定一个排序数组&#xff0c;你需要在原地删除重复出现的元素&#xff0c;使得每个元素只出现一次&#xff0c;返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 示例 1: 给定数组 nums [1,1,2…

leecode53 最大子序列和

给定一个整数数组 nums &#xff0c;找到一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 示例: 输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: 连续子数组 [4,-1,2,1] 的和最大&#xff0c;为 6。 思路&#xff1a;…

Github(3)-本地文件管理

使用github 托管代码简单使用教程--本地文件管理1.基本概念2.本地文件管理2.1 git add2.2 git status2.3 git commit2.3 git log2.5 git reset --hard 版本回退2.6 git reflog2.7 git diff2.8 git checkout --file 工作区文件恢复2.9 git rm 删除版本库里的文件廖雪峰老师博文学…

leecode62 不同路径

示例 1: 输入: m 3, n 2 输出: 3 解释: 从左上角开始&#xff0c;总共有 3 条路径可以到达右下角。 1. 向右 -> 向右 -> 向下 2. 向右 -> 向下 -> 向右 3. 向下 -> 向右 -> 向右 示例 2: 输入: m 7, n 3 输出: 28 思路&#xff1a;太过于简单&#xf…

leetcode64 最小路径和

给定一个包含非负整数的 m x n 网格&#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 说明&#xff1a;每次只能向下或者向右移动一步。 示例: 输入: [ [1,3,1], [1,5,1], [4,2,1] ] 输出: 7 解释: 因为路径 1→3→1→1→1 的总…