Linux下简易线程池

线程池简介

简易线程池实现

  线程池头文件threadpool.h如下:

 1 #ifndef THREADPOOL_H
 2 #define THREADPOOL_H
 3
 4 #include <stdio.h>
 5 #include <stdlib.h>
 6 #include <unistd.h>
 7 #include <pthread.h>
 8
 9 /**
10 * 线程体数据结构
11 */
12 typedef struct runner
13 {
14     void(*callback)(void* arg);    // 回调函数指针
15     void* arg;                     // 回调函数的参数
16     struct runner* next;
17 } thread_runner;
18
19 /**
20 * 线程池数据结构
21 */
22 typedef struct
23 {
24     pthread_mutex_t mutex;             // 互斥量
25     pthread_cond_t cond;               // 条件变量
26     thread_runner* runner_head;        // 线程池中所有等待任务的头指针
27     thread_runner* runner_tail;        // 线程池所有等待任务的尾指针
28     int shutdown;                      // 线程池是否销毁
29     pthread_t* threads;                // 所有线程
30     int max_thread_size;               // 线程池中允许的活动线程数目
31 } thread_pool;
32
33 /**
34 * 线程体
35 */
36 void run(void *arg);
37
38 /**
39 *   初始化线程池
40 *   参数:
41 *   pool:指向线程池结构有效地址的动态指针
42 *   max_thread_size:最大的线程数
43 */
44 void threadpool_init(thread_pool* pool, int max_thread_size);
45
46 /**
47 *   向线程池加入任务
48 *   参数:
49 *   pool:指向线程池结构有效地址的动态指针
50 *   callback:线程回调函数
51 *   arg:回调函数参数
52 */
53 void threadpool_add_runner(thread_pool* pool, void(*callback)(void *arg), void *arg);
54
55 /**
56 *   销毁线程池
57 *   参数:
58 *   ppool:指向线程池结构有效地址的动态指针地址(二级指针),销毁后释放内存,该指针为NULL
59 */
60 void threadpool_destroy(thread_pool** ppool);
61
62 #endif

  线程池实现文件threadpool.c如下:

  1 #include "threadpool.h"
  2
  3 #define DEBUG 1
  4
  5 /**
  6 *   初始化线程池
  7 *   参数:
  8 *   pool:指向线程池结构有效地址的动态指针
  9 *   max_thread_size:最大的线程数
 10 */
 11 void threadpool_init(thread_pool* pool, int max_thread_size)
 12 {
 13     // 初始化互斥量
 14     pthread_mutex_init(&(pool->mutex), NULL);
 15     // 初始化条件变量
 16     pthread_cond_init(&(pool->cond), NULL);
 17     pool->runner_head = NULL;
 18     pool->runner_tail = NULL;
 19     pool->max_thread_size = max_thread_size;
 20     pool->shutdown = 0;
 21
 22     // 创建所有分离态线程(即创建线程池)
 23     pool->threads = (pthread_t *)malloc(max_thread_size * sizeof(pthread_t));
 24     int i = 0;
 25     for (i = 0; i < max_thread_size; i++)
 26     {
 27         pthread_attr_t attr;
 28         pthread_attr_init(&attr);
 29         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 30         pthread_create(&(pool->threads[i]), &attr, (void*)run, (void*)pool);
 31     }
 32 #ifdef DEBUG
 33     printf("threadpool_init-> create %d detached thread\n", max_thread_size);
 34 #endif
 35 }
 36
 37 /**
 38 * 线程体
 39 */
 40 void run(void *arg)
 41 {
 42     thread_pool* pool = (thread_pool*)arg;
 43     while (1)
 44     {
 45         // 加锁
 46         pthread_mutex_lock(&(pool->mutex));
 47 #ifdef DEBUG
 48         printf("run-> locked\n");
 49 #endif
 50         // 如果等待队列为0并且线程池未销毁,则处于阻塞状态(即等待任务的唤醒)
 51         while (pool->runner_head == NULL && !pool->shutdown)
 52         {
 53             pthread_cond_wait(&(pool->cond), &(pool->mutex));
 54         }
 55         //如果线程池已经销毁
 56         if (pool->shutdown)
 57         {
 58             // 解锁
 59             pthread_mutex_unlock(&(pool->mutex));
 60 #ifdef DEBUG
 61             printf("run-> unlocked and thread exit\n");
 62 #endif
 63             pthread_exit(NULL);
 64         }
 65         // 取出链表中的头元素
 66         thread_runner *runner = pool->runner_head;
 67         pool->runner_head = runner->next;
 68         // 解锁
 69         pthread_mutex_unlock(&(pool->mutex));
 70 #ifdef DEBUG
 71         printf("run-> unlocked\n");
 72 #endif
 73         // 调用回调函数,执行任务
 74         (runner->callback)(runner->arg);
 75         free(runner);
 76         runner = NULL;
 77 #ifdef DEBUG
 78         printf("run-> runned and free runner\n");
 79 #endif
 80     }
 81     pthread_exit(NULL);
 82 }
 83
 84 /**
 85 *   向线程池加入任务
 86 *   参数:
 87 *   pool:指向线程池结构有效地址的动态指针
 88 *   callback:线程回调函数
 89 *   arg:回调函数参数
 90 */
 91 void threadpool_add_runner(thread_pool* pool, void(*callback)(void *arg), void *arg)
 92 {
 93     // 构造一个新任务
 94     thread_runner *newrunner = (thread_runner *)malloc(sizeof(thread_runner));
 95     newrunner->callback = callback;
 96     newrunner->arg = arg;
 97     newrunner->next = NULL;
 98     // 加锁
 99     pthread_mutex_lock(&(pool->mutex));
100 #ifdef DEBUG
101     printf("threadpool_add_runner-> locked\n");
102 #endif
103     // 将任务加入到等待队列中
104     if (pool->runner_head != NULL)
105     {
106         pool->runner_tail->next = newrunner;
107         // 尾指针指到最后一个任务
108         pool->runner_tail = newrunner;
109     }
110     else
111     {
112         pool->runner_head = newrunner;
113         pool->runner_tail = newrunner;
114     }
115     // 解锁
116     pthread_mutex_unlock(&(pool->mutex));
117 #ifdef DEBUG
118     printf("threadpool_add_runner-> unlocked\n");
119 #endif
120     // 唤醒一个等待线程
121     pthread_cond_signal(&(pool->cond));
122 #ifdef DEBUG
123     printf("threadpool_add_runner-> add a runner and wakeup a waiting thread\n");
124 #endif
125 }
126
127 /**
128 *   销毁线程池
129 *   参数:
130 *   ppool:指向线程池结构有效地址的动态指针地址(二级指针)
131 */
132 void threadpool_destroy(thread_pool** ppool)
133 {
134     thread_pool *pool = *ppool;
135     // 防止2次销毁
136     if (!pool->shutdown)
137     {
138         pool->shutdown = 1;
139         // 唤醒所有等待线程,线程池要销毁了
140         pthread_cond_broadcast(&(pool->cond));
141         // 等待所有线程中止
142         sleep(1);
143 #ifdef DEBUG
144         printf("threadpool_destroy-> wakeup all waiting threads\n");
145 #endif
146         // 回收空间
147         free(pool->threads);
148         // 销毁等待队列
149         thread_runner *head = NULL;
150         while (pool->runner_head != NULL)
151         {
152             head = pool->runner_head;
153             pool->runner_head = pool->runner_head->next;
154             free(head);
155         }
156
157 #ifdef DEBUG
158         printf("threadpool_destroy-> all runners freed\n");
159 #endif
160         // 条件变量和互斥量也别忘了销毁
161         pthread_mutex_destroy(&(pool->mutex));
162         pthread_cond_destroy(&(pool->cond));
163
164 #ifdef DEBUG
165         printf("threadpool_destroy-> mutex and cond destoryed\n");
166 #endif
167         free(pool);
168         (*ppool) = NULL;
169
170 #ifdef DEBUG
171         printf("threadpool_destroy-> pool freed\n");
172 #endif
173     }
174 }

  测试文件如下:

 1 #include "threadpool.h"
 2
 3 void threadrun(void* arg)
 4 {
 5     int *i = (int *)arg;
 6     printf("%d\n", *i);
 7 }
 8
 9 int main(void)
10 {
11     thread_pool *pool = malloc(sizeof(thread_pool));
12     threadpool_init(pool, 2);
13
14     int i;
15     int tmp[3];
16     for (i = 0; i < 3; i++)
17     {
18         tmp[i] = i;
19         threadpool_add_runner(pool, threadrun, &tmp[i]);
20     }
21
22     sleep(1);
23     threadpool_destroy(&pool);
24     printf("main-> %p\n", pool);
25     printf("main-> test over\n");
26
27     return 0;
28 }

  程序运行结果如下:

  

参考资料

  Linux线程池(C语言描述) - 互斥量+条件变量同步

时间: 2024-11-05 19:04:53

Linux下简易线程池的相关文章

linux下的线程池

什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了.如果线程创建和销毁时间相比任务执行时间可以忽略不计,则没有必要使用线程池了. 下面是Linux系统下用C语言创建的一个线程池.线程池会维护一个任务链表(每个CThread_worker结构就是一个任务).   pool_init()函数预先创建好max_thread_num个线程,每个线程执thread_routine ()函

一个Linux下C线程池的实现

在传统服务器结构中, 常是 有一个总的 监听线程监听有没有新的用户连接服务器, 每当有一个新的 用户进入, 服务器就开启一个新的线程用户处理这 个用户的数据包.这个线程只服务于这个用户 , 当 用户与服务器端关闭连接以后, 服务器端销毁这个线程.然而频繁地开辟与销毁线程极大地占用了系统的资源.而且在大量用户的情况下, 系统为了开辟和销毁线程将浪费大量的时间和资源.线程池提供了一个解决外部大量用户与服务器有限资源的矛盾, 线程池和传统的一个用户对应一个线程的处理方法不同, 它的基本思想就是在程序

Linux下简单线程池的实现

线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁.如何利用已有对象来服务(不止一个不同的任务)就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因.比如大家所熟悉的数据库连接池正是遵循这一思想而产生的,本文将介绍的线程池技术同

linux 下c++线程池的简单实现(在老外代码上添加注释)

作为一个c++菜鸟,研究半天这个代码的实现原理,发现好多语法不太熟悉,因此加了一大堆注释,仅供参考.该段代码主要通过继承workthread类来实现自己的线程代码,通过thread_pool类来管理线程池,线程池不能够实现动态改变线程数目,存在一定局限性.目前可能还有缺陷,毕竟c++来封装这个东西,资源释放什么的必须想清楚,比如vector存储了基类指针实现多态,那么如何释放对象仍需要考虑,后续我可能会更进一步修改完善该代码,下面贡献一下自己的劳动成果. #include <pthread.h>

简易“线程池”在Python网络爬虫中的应用

一,我是如何使用Python抓取网页的 我知道Python有一个爬虫框架scrapy,但是目前还没有学习,并且也没有什么很棘手的的问题需要去使用一个爬虫框架,所以我就用Python自带的urllib,将目标网页爬下来,然后用正则过滤出自己需要的内容. 二,效率问题 上面的方法简单,真的是上手即用,但是问题是效率问题,如果一个网页一个网页的抓,显然带宽无法达到最高,浪费了大部分带宽,这时候大部分人都会想到,多线程啊! 对,但是我们大部分人又都会写出下面的代码 # 总任务数有500个 while i

linux下简易搭建svnserver

参考文档: 安装部署: http://www.cnblogs.com/wrmfw/archive/2011/09/08/2170465.html http://www.ha97.com/4467.html 关闭服务: http://linux.chinaunix.net/techdoc/net/2005/08/17/923721.shtml 测试成功: http://blog.163.com/[email protected]/blog/static/1736123482012021142129

Linux下Java线程详细监控和其dump的分析使用----分析Java性能瓶颈

这里对linux下.sun(oracle) JDK的线程资源占用问题的查找步骤做一个小结: linux环境下,当发现java进程占用CPU资源很高,且又要想更进一步查出哪一个java线程占用了CPU资源时,按照以下步骤进行查找: (一):通过[top -p 12377 -H] 查看java进程的有哪些线程的运行情况:       和通过[jstack 12377 > stack.log]生成Java线程的dump详细信息: 先用top命令找出占用资源厉害的java进程id,如图:# top 如上

python笔记——简易线程池multiprocessing.Pool

多线程模型设计是一个比较复杂的逻辑,但是python对于多线程的处理却有种种方便的类库,不需要过多的纠结线程间的操作细节.比如multiprocessing.Pool就是其中之一. 官方给的范例也很简单. from multiprocessing import Pool def f(x): return x*x if __name__ == '__main__': pool = Pool(processes=4) # start 4 worker processes result = pool.

C++11下的线程池以及灵活的functional + bind + lamda

利用boost的thread实现一个线程类,维护一个任务队列,以便可以承载非常灵活的调用.这个线程类可以方便的为后面的线程池打好基础.线程池还是动态均衡,没有什么别的.由于minGW 4.7 对 C++11 thread 不支持,所以采用 boost 代替,linux 下是支持的,只是名字空间不同而已,套路都一样.先上代码: [cpp] view plaincopy #include #include <boost/thread/thread.hpp> #include <boost/t