热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C语言编写线程池的简单实现方法

2019独角兽企业重金招聘Python工程师标准好文章,一起分享——有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

好文章,一起分享——


有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带来的开销,我们可以使用线程池。下面是一个C语言实现的简单的线程池。

头文件:

1: #ifndef THREAD_POOL_H__

2: #define THREAD_POOL_H__

3: 

4: #include

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

2: #include

3: #include

4: #include

5: #include

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

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 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

2: #include

3: #include

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 &#61; 0; i <10; &#43;&#43;i) {

22: tpool_add_work(func, (void*)i);

23: }

24: sleep(2);

25: tpool_destroy();

26: return 0;

27: }

这个实现是在调用tpool_destroy之后&#xff0c;仅将当前正在执行的任务完成之后就会退出&#xff0c;我们也可以修改代码使得线程池在执行完任务链表中所有任务后再退出。


转:https://my.oschina.net/Bruce370/blog/391823



推荐阅读
  • golang常用库:配置文件解析库/管理工具viper使用
    golang常用库:配置文件解析库管理工具-viper使用-一、viper简介viper配置管理解析库,是由大神SteveFrancia开发,他在google领导着golang的 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
  • Codeforces Round #566 (Div. 2) A~F个人题解
    Dashboard-CodeforcesRound#566(Div.2)-CodeforcesA.FillingShapes题意:给你一个的表格,你 ... [详细]
  • 实体映射最强工具类:MapStruct真香 ... [详细]
  • 装饰器是一种用于在不修改原函数代码的情况下,动态地添加功能的工具。它允许你在函数执行前后插入额外的逻辑,从而增强或改变函数的行为。 ... [详细]
  • 本次考试于2016年10月25日上午7:50至11:15举行,主要涉及数学专题,特别是斐波那契数列的性质及其在编程中的应用。本文将详细解析考试中的题目,并提供解题思路和代码实现。 ... [详细]
  • 作者:守望者1028链接:https:www.nowcoder.comdiscuss55353来源:牛客网面试高频题:校招过程中参考过牛客诸位大佬的面经,但是具体哪一块是参考谁的我 ... [详细]
  • 本文详细探讨了KMP算法中next数组的构建及其应用,重点分析了未改良和改良后的next数组在字符串匹配中的作用。通过具体实例和代码实现,帮助读者更好地理解KMP算法的核心原理。 ... [详细]
  • 本文探讨了Hive中内部表和外部表的区别及其在HDFS上的路径映射,详细解释了两者的创建、加载及删除操作,并提供了查看表详细信息的方法。通过对比这两种表类型,帮助读者理解如何更好地管理和保护数据。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 数据管理权威指南:《DAMA-DMBOK2 数据管理知识体系》
    本书提供了全面的数据管理职能、术语和最佳实践方法的标准行业解释,构建了数据管理的总体框架,为数据管理的发展奠定了坚实的理论基础。适合各类数据管理专业人士和相关领域的从业人员。 ... [详细]
author-avatar
henrysong
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有