LINUX下的简单线程池
前言
任何一种设计方式的引入都会带来额外的开支,是否使用,取决于能带来多大的好处和能带来多大的坏处,好处与坏处包括程序的性能、代码的可读性、代码的可维护性、程序的开发效率等。
线程池适用场合:任务比较多,需要拉起大量线程来处理;任务的处理时间相对比较短,按照线程的周期T1(创建阶段)、T2(执行阶段)、T3(销毁阶段)来算,执行阶段仅占用较少时间。
简单的线程池通常有以下功能:预创建一定数量的线程;管理线程任务,当工作线程没有事情可做时休眠自己;销毁线程池。
复杂一些的线程池有额外的调节功能:管理线程池的上限;动态调节工作线程数量,当大量工作请求到来时增加工作线程,工作请求较少时销毁部分线程。
内容部分
这次实现的是一个简单的线程池模型。
首先是线程池的头文件定义:
1 #include<unistd.h>
2 #include<stdlib.h>
3 #include<iostream>
4 #include<string>
5 #include<string.h>
6 #include<queue>
7 #include<errno.h>
8 #include<pthread.h>
9 using namespace std;
10
11 struct thread_work
12 {
13 void* (*routine)(void*);
14 void* arg;
15 };
16
17 struct thread_pool
18 {
19 bool ShutDown;
20 unsigned int iMaxThreadNum;
21 pthread_mutex_t pool_mutex;
22 pthread_cond_t pool_cond;
23 queue<pthread_t> Pth_IdQueue;
24 queue<thread_work> Pth_workQueue;
25 };
26
27 thread_pool* thread_pool_create(int iThreadNum);
28 void thread_pool_destroy(thread_pool* thpool);
29 int thread_pool_add_task(thread_pool* thpool, void*(*routine)(void*), void* arg);
30 void* thread_routine(void* arg);
下面是线程池的实现:
2
3 thread_pool* thread_pool_create(int iThreadMaxNum)
4 {
5 int iRet = 0;
6 thread_pool* pool = new thread_pool;
7 if(NULL == pool)
8 {
9 cout << "new thread_pool failed! procedure exit" << endl;
10 return NULL;
11 }
12 pool->iMaxThreadNum = iThreadMaxNum;
13 pool->ShutDown = false;
14 if((iRet=pthread_mutex_init(&pool->pool_mutex, NULL)) != 0)
15 {
16 cout << __FUNCTION__ << "thread_pool init failed! error: " << strerror(iRet) << endl;
17 delete pool;
18 return NULL;
19 }
20 if((iRet=pthread_cond_init(&pool->pool_cond, NULL)) != 0)
21 {
22 cout << __FUNCTION__ << "thread_cond init failed! error: " << strerror(iRet) << endl;
23 delete pool;
24 return NULL;
25 }
26
27 for(int i = 0; i < iThreadMaxNum; i++)
28 {
29 pthread_t thid = 0;
30 if((iRet=pthread_create(&thid, NULL, thread_routine, (void*)pool)) != 0)
31 {
32 cout << __FUNCTION__ << " pthread_create failed, error: " << strerror(iRet) << endl;
33 delete pool;
34 return NULL;
35 }
36 else
37 {
38 pool->Pth_IdQueue.push(thid);
39 }
40 }
41 return pool;
42 }
43
44 int thread_pool_add_task(thread_pool* thpool, void*(*routine)(void*), void* arg)
45 {
46 if(routine == NULL || thpool == NULL)
47 return -1;
48 thread_work temp;
49 temp.routine = routine;
50 temp.arg = arg;
51 pthread_mutex_lock(&(thpool->pool_mutex));
52 thpool->Pth_workQueue.push(temp);
53 pthread_mutex_unlock(&(thpool->pool_mutex));
54 pthread_cond_signal(&(thpool->pool_cond));
55 return 0;
56 }
57
58 void thread_pool_destroy(thread_pool* thpool)
59 {
60 if(thpool == NULL)
61 return;
62 pthread_mutex_lock(&(thpool->pool_mutex));
63 thpool->ShutDown = true;
64 while(!thpool->Pth_workQueue.empty())
65 {
66 thpool->Pth_workQueue.pop();
67 }
68 pthread_cond_broadcast(&(thpool->pool_cond));
69 pthread_mutex_unlock(&(thpool->pool_mutex));
70 while(!thpool->Pth_IdQueue.empty())
71 {
72 pthread_join(thpool->Pth_IdQueue.front(), NULL);
73 thpool->Pth_IdQueue.pop();
74 }
75 pthread_mutex_destroy(&(thpool->pool_mutex));
76 pthread_cond_destroy(&(thpool->pool_cond));
77 delete thpool;
78 }
79
80 void* thread_routine(void* pool)
81 {
82 if(pool == NULL)
83 {
84 cout << "thread_routine params is empty, thread_exit" << endl;
85 return NULL;
86 }
87 while(1)
88 {
89 thread_pool* p = (thread_pool*)pool;
90 pthread_mutex_lock(&(p->pool_mutex));
91 while(p->Pth_workQueue.empty() && !p->ShutDown)
92 {
93 pthread_cond_wait(&(p->pool_cond), &(p->pool_mutex));
94 }
95 if(p->ShutDown)
96 {
97 pthread_mutex_unlock(&(p->pool_mutex));
98 return NULL;
99 }
100 thread_work work_f;
101 work_f = p->Pth_workQueue.front();
102 p->Pth_workQueue.pop();
103 pthread_mutex_unlock(&(p->pool_mutex));
104 work_f.routine(work_f.arg);
105 }
106 }
代码都是基础知识,大家应该都能理解。
下面是一个测试的demo:
1 #include "ThreadPool.h"
2
3 void* task(void* p)
4 {
5 int ptI = *(int*)p;
6 //cout << "ptr address : " << p << "ptr value : " << ptI << endl;
7 cout << ptI << endl;
8 return NULL;
9 }
10
11 int main()
12 {
13 struct thread_pool* pool = thread_pool_create(100);
14 int iArg[1000];
15 for(int i = 0; i < 1000; i++)
16 {
17 iArg[i] = i;
18 thread_pool_add_task(pool, task, &iArg[i]);
19 //cout << "thread_pool_add_task id: " << iArg[i] << endl;
20 //cout << __FUNCTION__ << " success, current task id is: " << iArg[i] << "iArg[" << i << "] address : " << &iArg[i] << endl;
21 }
22 thread_pool_destroy(pool);
23 }
小结
很简单很好理解的一段代码,我却写了大半天时间,手残党鉴定完毕。
LINUX下的简单线程池的更多相关文章
- 在Linux下写一个线程池以及线程池的一些用法和注意点
-->线程池介绍(大部分来自网络) 在这个部分,详细的介绍一下线程池的作用以及它的技术背景以及他提供的一些服务等.大部分内容来自我日常生活中在网络中学习到的一些概念性的东西. -->代码 ...
- Linux下简单线程池的实现
大多数的网络服务器,包括Web服务器都具有一个特点,就是单位时间内必须处理数目巨大的连接请求,但是处理时间却是比较短的.在传统的多线程服务器模型中是这样实现的:一旦有个服务请求到达,就创建一个新的服务 ...
- Linux多线程实践(9) --简单线程池的设计与实现
线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以 ...
- Linux下一个简单的日志系统的设计及其C代码实现
1.概述 在大型软件系统中,为了监测软件运行状况及排查软件故障,一般都会要求软件程序在运行的过程中产生日志文件.在日志文件中存放程序流程中的一些重要信息, 包括:变量名称及其值.消息结构定义.函数返回 ...
- linux 条件变量与线程池
条件变量Condition Variables 概述 1. 条件变量提供了另外一种线程同步的方式.如果没有条件变量,程序需要使用线程连续轮询(可能在临界区critical section内)方式检查条 ...
- 基于C++11的100行实现简单线程池
基于C++11的100行实现简单线程池 1 线程池原理 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小, ...
- Windows和Linux下通用的线程接口
对于多线程开发,Linux下有pthread线程库,使用起来比较方便,而Windows没有,对于涉及到多线程的跨平台代码开发,会带来不便.这里参考网络上的一些文章,整理了在Windows和Linux下 ...
- linux下c语言实现简单----线程池
这两天刚好看完linux&c这本书的进程线程部分,学长建议可以用c语言实现一个简单的线程池,也是对线程知识的一个回顾与应用.线程的优点有好多,它是"轻量级的进程",所需资源 ...
- 基于Linux/C++简单线程池的实现
我们知道Java语言对于多线程的支持十分丰富,JDK本身提供了很多性能优良的库,包括ThreadPoolExecutor和ScheduleThreadPoolExecutor等.C++11中的STL也 ...
随机推荐
- D3DXCOLOR 和 D3DCOLOR 和 D3DCOLORVALUE
D3DCOLOR 是一个DWORD 型.第一个byte表示Alpha值,后面三个byte依次是r(红)g(绿)b(蓝)值.32位. 下面是一些关于D3DCOLOR 的宏: D3DCOLOR_ARGB( ...
- CSS+DIV布局初练—DIV元素必须成对出现?
一直做C/S开发的工作,但是很少做和布局相关的工作,往往都是同事将界面设计好,自己填写代码而已,对于B/S的工作,做过,但是很少没有像C/S这么多,界面布局的话,更无从谈起. 日子就这么过,一天一个样 ...
- 【Java】JTable组件的构造函数和设置列宽
使用JTable组件 类层次结构图: java.lang.Object --java.awt.Component --java.awt.Container --javax.swing.JCompone ...
- mysqld -install命令时出现install/remove of the service denied错误的原因和解决办法
原因:没有使用管理员权限 解决方法:使用管理员权限打开cmd,然后运行mysqld -install,服务安装成功
- Target host is not specified错误
对于httpClient4.3访问指定页面,可以从下面的demo抽取方法使用. 注意:对于URL必须使用 http://开始,否则会有如下报错信息: 或者在设置cookie时带上domain: coo ...
- 使用Powermock进行单元测试,以及常见问题的处理
1. 引言 在进行单元测试时,经常遇到被测方法依赖外部对象和环境,如需要数据库连接,网络通信依赖等,需要进行大量的初始化工作,这时可以采用powermock+mockito对被测对象进行模拟,通过录放 ...
- [C#] 我的log4net使用手册
1. log4net简介 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.Java平台下,它还 ...
- redis作为mysql的缓存服务器(读写分离,通过mysql触发器实现数据同步)
一.redis简介Redis是一个key-value存储系统.和Memcached类似,为了保证效率,数据都是缓存在内存中.区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录 ...
- POJ 3683 Priest John's Busiest Day (2-SAT,常规)
题意: 一些人要在同一天进行婚礼,但是牧师只有1个,每一对夫妻都有一个时间范围[s , e]可供牧师选择,且起码要m分钟才主持完毕,但是要么就在 s 就开始,要么就主持到刚好 e 结束.因为人数太多了 ...
- varchar与nvarchar的区别
nvarchar可变长度的Unicode字符数据 varchar可变长度且非 Unicode 的字符数据 举例: varchar(1) --可以插进入一个数字或者一个字母,如果要插入一个汉字改为v ...