C语言实现简单线程池(转-Newerth)
有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带来的开销,我们可以使用线程池。下面是一个C语言实现的简单的线程池。
头文件:
1: #ifndef THREAD_POOL_H__
2: #define THREAD_POOL_H__
3:
4: #include <pthread.h>
5:
6: /* 要执行的任务链表 */
7: typedef struct tpool_work {
8: void* (*routine)(void*); /* 任务函数 */
9: void *arg; /* 传入任务函数的参数 */
10: struct tpool_work *next;
11: }tpool_work_t;
12:
13: typedef struct tpool {
14: int shutdown; /* 线程池是否销毁 */
15: int max_thr_num; /* 最大线程数 */
16: pthread_t *thr_id; /* 线程ID数组 */
17: tpool_work_t *queue_head; /* 线程链表 */
18: pthread_mutex_t queue_lock;
19: pthread_cond_t queue_ready;
20: }tpool_t;
21:
22: /*
23: * @brief 创建线程池
24: * @param max_thr_num 最大线程数
25: * @return 0: 成功 其他: 失败
26: */
27: int
28: tpool_create(int max_thr_num);
29:
30: /*
31: * @brief 销毁线程池
32: */
33: void
34: tpool_destroy();
35:
36: /*
37: * @brief 向线程池中添加任务
38: * @param routine 任务函数指针
39: * @param arg 任务函数参数
40: * @return 0: 成功 其他:失败
41: */
42: int
43: tpool_add_work(void*(*routine)(void*), void *arg);
44:
45: #endif
实现:
1: #include <unistd.h>
2: #include <stdlib.h>
3: #include <errno.h>
4: #include <string.h>
5: #include <stdio.h>
6:
7: #include "tpool.h"
8:
9: static tpool_t *tpool = NULL;
10:
11: /* 工作者线程函数, 从任务链表中取出任务并执行 */
12: static void*
13: thread_routine(void *arg)
14: {
15: tpool_work_t *work;
16:
17: while(1) {
18: /* 如果线程池没有被销毁且没有任务要执行,则等待 */
19: pthread_mutex_lock(&tpool->queue_lock);
20: while(!tpool->queue_head && !tpool->shutdown) {
21: pthread_cond_wait(&tpool->queue_ready, &tpool->queue_lock);
22: }
23: if (tpool->shutdown) {
24: pthread_mutex_unlock(&tpool->queue_lock);
25: pthread_exit(NULL);
26: }
27: work = tpool->queue_head;
28: tpool->queue_head = tpool->queue_head->next;
29: pthread_mutex_unlock(&tpool->queue_lock);
30:
31: work->routine(work->arg);
32: free(work);
33: }
34:
35: return NULL;
36: }
37:
38: /*
39: * 创建线程池
40: */
41: int
42: tpool_create(int max_thr_num)
43: {
44: int i;
45:
46: tpool = calloc(1, sizeof(tpool_t));
47: if (!tpool) {
48: printf("%s: calloc failed\n", __FUNCTION__);
49: exit(1);
50: }
51:
52: /* 初始化 */
53: tpool->max_thr_num = max_thr_num;
54: tpool->shutdown = 0;
55: tpool->queue_head = NULL;
56: if (pthread_mutex_init(&tpool->queue_lock, NULL) !=0) {
57: printf("%s: pthread_mutex_init failed, errno:%d, error:%s\n",
58: __FUNCTION__, errno, strerror(errno));
59: exit(1);
60: }
61: if (pthread_cond_init(&tpool->queue_ready, NULL) !=0 ) {
62: printf("%s: pthread_cond_init failed, errno:%d, error:%s\n",
63: __FUNCTION__, errno, strerror(errno));
64: exit(1);
65: }
66:
67: /* 创建工作者线程 */
68: tpool->thr_id = calloc(max_thr_num, sizeof(pthread_t));
69: if (!tpool->thr_id) {
70: printf("%s: calloc failed\n", __FUNCTION__);
71: exit(1);
72: }
73: for (i = 0; i < max_thr_num; ++i) {
74: if (pthread_create(&tpool->thr_id[i], NULL, thread_routine, NULL) != 0){
75: printf("%s:pthread_create failed, errno:%d, error:%s\n", __FUNCTION__,
76: errno, strerror(errno));
77: exit(1);
78: }
79:
80: }
81:
82: return 0;
83: }
84:
85: /* 销毁线程池 */
86: void
87: tpool_destroy()
88: {
89: int i;
90: tpool_work_t *member;
91:
92: if (tpool->shutdown) {
93: return;
94: }
95: tpool->shutdown = 1;
96:
97: /* 通知所有正在等待的线程 */
98: pthread_mutex_lock(&tpool->queue_lock);
99: pthread_cond_broadcast(&tpool->queue_ready);
100: pthread_mutex_unlock(&tpool->queue_lock);
101: for (i = 0; i < tpool->max_thr_num; ++i) {
102: pthread_join(tpool->thr_id[i], NULL);
103: }
104: free(tpool->thr_id);
105:
106: while(tpool->queue_head) {
107: member = tpool->queue_head;
108: tpool->queue_head = tpool->queue_head->next;
109: free(member);
110: }
111:
112: pthread_mutex_destroy(&tpool->queue_lock);
113: pthread_cond_destroy(&tpool->queue_ready);
114:
115: free(tpool);
116: }
117:
118: /* 向线程池添加任务 */
119: int
120: tpool_add_work(void*(*routine)(void*), void *arg)
121: {
122: tpool_work_t *work, *member;
123:
124: if (!routine){
125: printf("%s:Invalid argument\n", __FUNCTION__);
126: return -1;
127: }
128:
129: work = malloc(sizeof(tpool_work_t));
130: if (!work) {
131: printf("%s:malloc failed\n", __FUNCTION__);
132: return -1;
133: }
134: work->routine = routine;
135: work->arg = arg;
136: work->next = NULL;
137:
138: pthread_mutex_lock(&tpool->queue_lock);
139: member = tpool->queue_head;
140: if (!member) {
141: tpool->queue_head = work;
142: } else {
143: while(member->next) {
144: member = member->next;
145: }
146: member->next = work;
147: }
148: /* 通知工作者线程,有新任务添加 */
149: pthread_cond_signal(&tpool->queue_ready);
150: pthread_mutex_unlock(&tpool->queue_lock);
151:
152: return 0;
153: }
154:
155:
测试代码:
1: #include <unistd.h>
2: #include <stdio.h>
3: #include <stdlib.h>
4: #include "tpool.h"
5:
6: void *func(void *arg)
7: {
8: printf("thread %d\n", (int)arg);
9: return NULL;
10: }
11:
12: int
13: main(int arg, char **argv)
14: {
15: if (tpool_create(5) != 0) {
16: printf("tpool_create failed\n");
17: exit(1);
18: }
19:
20: int i;
21: for (i = 0; i < 10; ++i) {
22: tpool_add_work(func, (void*)i);
23: }
24: sleep(2);
25: tpool_destroy();
26: return 0;
27: }
这个实现是在调用tpool_destroy之后,仅将当前正在执行的任务完成之后就会退出,我们也可以修改代码使得线程池在执行完任务链表中所有任务后再退出。
备注:这个实现有一定问题。在main函数中, 如果把sleep(2)去掉的话,main thread会destroy首先整个线程池,以至于创建的线程一个工作也不会做。对于追求性能的应用程序来说,先让主线程休眠等待创建的线程2秒钟来完成工作是无法忍受的。可以稍微改进一下让主线程不需休眠。
C语言实现简单线程池(转-Newerth)的更多相关文章
- linux下c语言实现简单----线程池
这两天刚好看完linux&c这本书的进程线程部分,学长建议可以用c语言实现一个简单的线程池,也是对线程知识的一个回顾与应用.线程的优点有好多,它是"轻量级的进程",所需资源 ...
- Linux下简单线程池的实现
大多数的网络服务器,包括Web服务器都具有一个特点,就是单位时间内必须处理数目巨大的连接请求,但是处理时间却是比较短的.在传统的多线程服务器模型中是这样实现的:一旦有个服务请求到达,就创建一个新的服务 ...
- Linux多线程实践(9) --简单线程池的设计与实现
线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以 ...
- 基于C++11的100行实现简单线程池
基于C++11的100行实现简单线程池 1 线程池原理 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小, ...
- 基于Linux/C++简单线程池的实现
我们知道Java语言对于多线程的支持十分丰富,JDK本身提供了很多性能优良的库,包括ThreadPoolExecutor和ScheduleThreadPoolExecutor等.C++11中的STL也 ...
- C++11的简单线程池代码阅读
这是一个简单的C++11实现的线程池,代码很简单. 原理就是管理一个任务队列和一个工作线程队列. 工作线程不断的从任务队列取任务,然后执行.如果没有任务就等待新任务的到来.添加新任务的时候先添加到任务 ...
- LINUX下的简单线程池
前言 任何一种设计方式的引入都会带来额外的开支,是否使用,取决于能带来多大的好处和能带来多大的坏处,好处与坏处包括程序的性能.代码的可读性.代码的可维护性.程序的开发效率等. 线程池适用场合:任务比较 ...
- c++简单线程池实现
线程池,简单来说就是有一堆已经创建好的线程(最大数目一定),初始时他们都处于空闲状态,当有新的任务进来,从线程池中取出一个空闲的线程处理任务,然后当任务处理完成之后,该线程被重新放回到线程池中,供其他 ...
- c++简单线程池实现(转)
线程池,简单来说就是有一堆已经创建好的线程(最大数目一定),初始时他们都处于空闲状态,当有新的任务进来,从线程池中取出一个空闲的线程处理任务,然后当任务处理完成之后,该线程被重新放回到线程池中,供其他 ...
随机推荐
- [Prodinner项目]学习分享_第三部分_Service层(业务逻辑层)
前两节讲到怎样生成一个Model和怎样将Model映射到数据库,这一节将讲到业务逻辑层,也就是Service层. 1.Prodinner架构已经构建好的,基本的增删改查. 假设,我现在想操作第二节中讲 ...
- Oracle PL/SQL实战代码下载
最近在学习PL/SQL编程,算是一个进阶吧,书没带光盘,所以按照书中的地址去下载样例,无法下载,到图灵官网找到了源代码下载地址,无法下载的留邮箱,我发给大家 下载地址: http://www.itur ...
- WebSocket实战之————GatewayWorker使用笔记例子
参考文档:http://www.workerman.net/gatewaydoc/ 目录结构 ├── Applications // 这里是所有开发者应用项目 │ └── YourApp // 其中一 ...
- Android handler 详解(面试百分之100问到)
handler在Android中被称为“消息处理者”,在多线程中比较常用. handler内部实现原理 handler实现机制:1,Message对象,表示要传递的一个消息,内部使用链表数据结构实现一 ...
- Caché数据库学习笔记(3)
目录 Query函数及其测试 重建索引表 Management portal简介 远程访问Ensemble ============================================== ...
- shell中&&和||的使用方法
测试题: [ -z "" ] && echo 0 || echo 1 的结果是多少 看看这两个 && || 的用户 http://blog.csd ...
- Android开发--EditText的应用
1.简介 EditText主要用于数据的输入,验证等问题.例如,账号的注册,验证等等. 2.构建 如下图所示,在Text Fields有多种类型的数据输入框,我们创建图2所示的文本框,当点击按钮时,文 ...
- input框限制只能输入正整数,逻辑与和或运算
推荐下自己刚写的项目,请大家指正:童话之翼 有时需要限制文本框输入内容的类型,本节分享下正则表达式限制文本框只能输入数字.小数点.英文字母.汉字等代码. 例如,输入大于0的正整数 代码如下: < ...
- SqlServer和MySQL游标学习
一 sqlserver游标使用 /*** 游标的使用 讲了这个多游标的优点,现在我们就亲自来揭开游标的神秘的面纱. 使用游标的顺序: 声名游标.打开游标.读取数据.关闭游标.删除游标. 1.3.1 ...
- cocos2d-x 中的基本概念
在 cocos2d-x 开头配置(Windows 平台)中,介绍了新建工程,这篇就介绍下 cocos2d-x 的一些概念.(前提是需要有C++的面向对象的基本知识和C++11的常用知识) 层,场景,导 ...