当前位置: 首页 > 编程日记 > 正文

Linux下C语言线程池的实现(1)

http://hi.baidu.com/lingiloveyou/blog/item/21e57cf3322a6b40342accc7.html

什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了。如果线程创建和销毁时间相比任务执行时间可以忽略不计,则没有必要使用线程池了。

   下面是Linux系统下用C语言创建的一个线程池。线程池会维护一个任务链表(每个CThread_worker结构就是一个任务)。
   pool_init()函数预先创建好max_thread_num个线程,每个线程执thread_routine ()函数。该函数中
  1. while (pool->cur_queue_size == 0)
  2. {
  3.        pthread_cond_wait (&(pool->queue_ready),&(pool->queue_lock));
  4. }
表示如果任务链表中没有任务,则该线程出于阻塞等待状态。否则从队列中取出任务并执行。
   
   pool_add_worker()函数向线程池的任务链表中加入一个任务,加入后通过调用pthread_cond_signal (&(pool->queue_ready))唤醒一个出于阻塞状态的线程(如果有的话)。
   
   pool_destroy ()函数用于销毁线程池,线程池任务链表中的任务不会再被执行,但是正在运行的线程会一直把任务运行完后再退出。

下面贴出完整代码
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/types.h>
  5. #include <pthread.h>
  6. #include <assert.h>

  7. /*
  8. *线程池里所有运行和等待的任务都是一个CThread_worker
  9. *由于所有任务都在链表里,所以是一个链表结构
  10. */
  11. typedef struct worker
  12. {
  13.     /*回调函数,任务运行时会调用此函数,注意也可声明成其它形式*/
  14.     void *(*process) (void *arg);
  15.     void *arg;/*回调函数的参数*/
  16.     struct worker *next;

  17. } CThread_worker;


  18. /*线程池结构*/
  19. typedef struct
  20. {
  21.      pthread_mutex_t queue_lock;
  22.      pthread_cond_t queue_ready;

  23.     /*链表结构,线程池中所有等待任务*/
  24.      CThread_worker *queue_head;

  25.     /*是否销毁线程池*/
  26.     int shutdown;
  27.      pthread_t *threadid;
  28.     /*线程池中允许的活动线程数目*/
  29.     int max_thread_num;
  30.     /*当前等待队列的任务数目*/
  31.     int cur_queue_size;

  32. } CThread_pool;


  33. int pool_add_worker (void *(*process) (void *arg), void *arg);
  34. void *thread_routine (void *arg);


  35. static CThread_pool *pool = NULL;
  36. void
  37. pool_init (int max_thread_num)
  38. {
  39.      pool = (CThread_pool *) malloc (sizeof (CThread_pool));

  40.      pthread_mutex_init (&(pool->queue_lock), NULL);
  41.      pthread_cond_init (&(pool->queue_ready), NULL);

  42.      pool->queue_head = NULL;

  43.      pool->max_thread_num = max_thread_num;
  44.      pool->cur_queue_size = 0;

  45.      pool->shutdown = 0;

  46.      pool->threadid =
  47.          (pthread_t *) malloc (max_thread_num * sizeof (pthread_t));
  48.     int i = 0;
  49.     for (i = 0; i < max_thread_num; i++)
  50.      {
  51.          pthread_create (&(pool->threadid[i]), NULL, thread_routine,
  52.                  NULL);
  53.      }
  54. }


  55. /*向线程池中加入任务*/
  56. int
  57. pool_add_worker (void *(*process) (void *arg), void *arg)
  58. {
  59.     /*构造一个新任务*/
  60.      CThread_worker *newworker =
  61.          (CThread_worker *) malloc (sizeof (CThread_worker));
  62.      newworker->process = process;
  63.      newworker->arg = arg;
  64.      newworker->next = NULL;/*别忘置空*/

  65.      pthread_mutex_lock (&(pool->queue_lock));
  66.     /*将任务加入到等待队列中*/
  67.      CThread_worker *member = pool->queue_head;
  68.     if (member != NULL)
  69.      {
  70.         while (member->next != NULL)
  71.              member = member->next;
  72.          member->next = newworker;
  73.      }
  74.     else
  75.      {
  76.          pool->queue_head = newworker;
  77.      }

  78.      assert (pool->queue_head != NULL);

  79.      pool->cur_queue_size++;
  80.      pthread_mutex_unlock (&(pool->queue_lock));
  81.     /*好了,等待队列中有任务了,唤醒一个等待线程;
  82.      注意如果所有线程都在忙碌,这句没有任何作用*/
  83.      pthread_cond_signal (&(pool->queue_ready));
  84.     return 0;
  85. }


  86. /*销毁线程池,等待队列中的任务不会再被执行,但是正在运行的线程会一直
  87. 把任务运行完后再退出*/
  88. int
  89. pool_destroy ()
  90. {
  91.     if (pool->shutdown)
  92.         return -1;/*防止两次调用*/
  93.      pool->shutdown = 1;

  94.     /*唤醒所有等待线程,线程池要销毁了*/
  95.      pthread_cond_broadcast (&(pool->queue_ready));

  96.     /*阻塞等待线程退出,否则就成僵尸了*/
  97.     int i;
  98.     for (i = 0; i < pool->max_thread_num; i++)
  99.          pthread_join (pool->threadid[i], NULL);
  100.      free (pool->threadid);

  101.     /*销毁等待队列*/
  102.      CThread_worker *head = NULL;
  103.     while (pool->queue_head != NULL)
  104.      {
  105.          head = pool->queue_head;
  106.          pool->queue_head = pool->queue_head->next;
  107.          free (head);
  108.      }
  109.     /*条件变量和互斥量也别忘了销毁*/
  110.      pthread_mutex_destroy(&(pool->queue_lock));
  111.      pthread_cond_destroy(&(pool->queue_ready));
  112.     
  113.      free (pool);
  114.     /*销毁后指针置空是个好习惯*/
  115.      pool=NULL;
  116.     return 0;
  117. }


  118. void *
  119. thread_routine (void *arg)
  120. {
  121.      printf ("starting thread 0x%x\n", pthread_self ());
  122.     while (1)
  123.      {
  124.          pthread_mutex_lock (&(pool->queue_lock));
  125.         /*如果等待队列为0并且不销毁线程池,则处于阻塞状态; 注意
  126.          pthread_cond_wait是一个原子操作,等待前会解锁,唤醒后会加锁*/
  127.         while (pool->cur_queue_size == 0 && !pool->shutdown)
  128.          {
  129.              printf ("thread 0x%x is waiting\n", pthread_self ());
  130.              pthread_cond_wait (&(pool->queue_ready), &(pool->queue_lock));
  131.          }

  132.         /*线程池要销毁了*/
  133.         if (pool->shutdown)
  134.          {
  135.             /*遇到break,continue,return等跳转语句,千万不要忘记先解锁*/
  136.              pthread_mutex_unlock (&(pool->queue_lock));
  137.              printf ("thread 0x%x will exit\n", pthread_self ());
  138.              pthread_exit (NULL);
  139.          }

  140.          printf ("thread 0x%x is starting to work\n", pthread_self ());

  141.         /*assert是调试的好帮手*/
  142.          assert (pool->cur_queue_size != 0);
  143.          assert (pool->queue_head != NULL);
  144.         
  145.         /*等待队列长度减去1,并取出链表中的头元素*/
  146.          pool->cur_queue_size--;
  147.          CThread_worker *worker = pool->queue_head;
  148.          pool->queue_head = worker->next;
  149.          pthread_mutex_unlock (&(pool->queue_lock));

  150.         /*调用回调函数,执行任务*/
  151.          (*(worker->process)) (worker->arg);
  152.          free (worker);
  153.          worker = NULL;
  154.      }
  155.     /*这一句应该是不可达的*/
  156.      pthread_exit (NULL);
  157. }

    下面是测试代码
  1. void *
  2. myprocess (void *arg)
  3. {
  4.      printf ("threadid is 0x%x, working on task %d\n", pthread_self (),*(int *) arg);
  5.      sleep (1);/*休息一秒,延长任务的执行时间*/
  6.     return NULL;
  7. }

  8. int
  9. main (int argc, char **argv)
  10. {
  11.      pool_init (3);/*线程池中最多三个活动线程*/
  12.     
  13.     /*连续向池中投入10个任务*/
  14.     int *workingnum = (int *) malloc (sizeof (int) * 10);
  15.     int i;
  16.     for (i = 0; i < 10; i++)
  17.      {
  18.          workingnum[i] = i;
  19.          pool_add_worker (myprocess, &workingnum[i]);
  20.      }
  21.     /*等待所有任务完成*/
  22.      sleep (5);
  23.     /*销毁线程池*/
  24.      pool_destroy ();

  25.      free (workingnum);
  26.     return 0;
  27. }
将上述所有代码放入threadpool.c文件中,
在Linux输入编译命令
$ gcc -o threadpool threadpool.c -lpthread

以下是运行结果
starting thread 0xb7df6b90
thread 0xb7df6b90 is waiting
starting thread 0xb75f5b90
thread 0xb75f5b90 is waiting
starting thread 0xb6df4b90
thread 0xb6df4b90 is waiting
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 0
thread 0xb75f5b90 is starting to work
threadid is 0xb75f5b90, working on task 1
thread 0xb6df4b90 is starting to work
threadid is 0xb6df4b90, working on task 2
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 3
thread 0xb75f5b90 is starting to work
threadid is 0xb75f5b90, working on task 4
thread 0xb6df4b90 is starting to work
threadid is 0xb6df4b90, working on task 5
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 6
thread 0xb75f5b90 is starting to work
threadid is 0xb75f5b90, working on task 7
thread 0xb6df4b90 is starting to work
threadid is 0xb6df4b90, working on task 8
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 9
thread 0xb75f5b90 is waiting
thread 0xb6df4b90 is waiting
thread 0xb7df6b90 is waiting
thread 0xb75f5b90 will exit
thread 0xb6df4b90 will exit
thread 0xb7df6b90 will exit

转载于:https://www.cnblogs.com/balaamwe/archive/2012/01/06/2315073.html

相关文章:

一篇简单易懂的原理文章,让你把JVM玩弄与手掌之中

jvm原理 Java虚拟机是整个java平台的基石&#xff0c;是java技术实现硬件无关和操作系统无关的关键环节&#xff0c;是java语言生成极小体积的编译代码的运行平台&#xff0c;是保护用户机器免受恶意代码侵袭的保护屏障。JVM是虚拟机&#xff0c;也是一种规范&#xff0c;他遵循…

python代码画皮卡丘_Python气象绘图实例我们一起画台风(代码+数据)

前段时间袭击中国的超强台风“利奇马”&#xff0c;以及这两天袭击美国的五级飓风“多利安”&#xff0c;让我们感受到了大自然的力量。所以&#xff0c;今天分享一个简单的Python实例&#xff0c;也算是延续前面python气象绘图系列(点击链接1&#xff1b;点击链接2)&#xff0…

Windows Socket编程笔记之最简单的小Demo

Windows Socket编程的大致过程:服务器端:----过程-------------对应的API------- 0.初始化 | WSAStartup() 1.创建Socket | socket() 2.绑定Socket | bind() 3.监听 | listen() 4.接受连接 | accept() 5.接收/发送数据 | recv()/send()…

React项目实战

一、环境搭建 1.安装react-cli脚手架&#xff08;保证提前安装好Node最新版本&#xff09; npm config set registry http://registry.npm.taobao.org/ npm config set sass-binary-site http://npm.taobao.org/mirrors/node-sass npm isntall -g create-react-app 2.查看react…

win7完美兼容DynamipsGUI(小凡模拟器)攻略

博主又是好久没写了&#xff0c;今天闲来无事与大家一起分享一下如何在windows7平台下完美兼容DynamipsGUI&#xff08;小凡模拟器&#xff09;的一个小窍门~ 对于学习cisco的朋友来说&#xff0c;DynamipsGUI&#xff08;小凡模拟器&#xff09;一定不陌生&#xff0c;在这就不…

使用PHPExcel 对表格进行,读取和写入的操作。。。。

下面的代码是使用PHPExcel 对多个表格数据进行读取&#xff0c; 然后整合的写入新的表格的方法&#xff01;&#xff01;&#xff01;代码有点粗糙 &#xff0c; 多多保函&#xff01;&#xff01;&#xff01; 这里有些地方注意下&#xff0c;如果你的表格数据过大&#xff0c…

c# .netframwork 4.0 调用 2.0时报错 混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集。...

“System.IO.FileLoadException”类型的未经处理的异常在 XXX.dll 中发生 其他信息: 混合模式程序集是针对“v2.0.50727”版的运行时生成的&#xff0c;在没有配置其他信息的情况下&#xff0c;无法在 4.0 运行时中加载该程序集。 这时需要改dbconfig配置 在configuration 节点…

python多线程并发_Python进阶记录之基础篇(二十四)

回顾在Python进阶记录之基础篇(二十三)中&#xff0c;我们介绍了进程的基本概念以及Python中多进程的基本使用方法。其中&#xff0c;需要重点掌握多进程的创建方法、进程池和进程间的通信。今天我们讲一下Python中的多线程。线程的基本概念线程是操作系统能够进行运算调度的最…

awk处理文件内容格式

今天运营出了点问题&#xff0c;需要对特定时间段充值数做一个处理&#xff0c;文件格式有特定要求&#xff0c;要符合erlang的格式{roleID,gold}.mysql导出所有数据结果如下【取部分数据看】&#xff1a;kuwo 4 50004106230500 100kuwo 4 50004106230900 …

QQ远程协助没动静?QQ版本有讲究

一位网友觉得电脑反应速度慢了&#xff0c;想通过QQ远程协助让我处理一下。不料接受请求后&#xff0c;等了许久都显示网友电脑的桌面&#xff0c;而网友那边QQ也没有任何提示。 反复尝试了几次都是如此。 询问网友得知他用的QQ为2011版&#xff0c;而我使用的QQ是2008版。难…

java课堂测试样卷-----简易学籍管理系统

程序设计思路&#xff1a;分别建立两个类&#xff1a;ScoreInformation类(用来定义学生的基本信息以及设置set和get函数&#xff09;ScoreManagement类&#xff08;用来定义实现学生考试成绩录入&#xff0c;考试成绩修改&#xff0c;绩点计算等功能的函数&#xff09;和一个主…

python3安装setuptools步骤_setuptools、pip的安装

第2篇分享 安装setuptools 下载setuptools源码setuptools-25.2.0.tar.gz选择需要的版本 这是一个压缩文件&#xff0c;将其解压到桌面&#xff0c;并进入该文件夹 按住shift键后&#xff0c;在文件夹空白处点击鼠标右键&#xff0c;选择&#xff1a;在此处打开命令窗重点&#…

如何将简单CMS后台管理系统示例转换为Java、Php等不同后台语言的版本

等下要去坐车&#xff0c;今天就不继续唠叨开发过程了&#xff0c;来谈一下普遍比较关心的后台语言问题。学习Ext JS&#xff0c;笔者一直强调学习的中心思路是“界面与数据是分离”。只要好好掌握这个思路&#xff0c;深入了解Ext JS的运作过程&#xff0c;就不会为后台语言使…

[面试]future模式

Future模式 什么是future模式? 传统单线程环境下&#xff0c;调用函数是同步的&#xff0c;必须等待程序返回结果后&#xff0c;才可进行其他处理。 Futrue模式下&#xff0c;调用方式改为异步。 Futrue模式的核心在于&#xff1a;充分利用主函数中的等待时间&#xff0c;利用…

java ide

tidespringsource sts a vmware product plugin:Aptana Studio 3(集成了Git) Run on Jettyeclipse for jee plugin:JBoss Tools,m2eclipe,spirng tools,svn

成长秘笈:是你教我,不是我教你

郑昀 20180622 “谢谢你&#xff0c;你是第一个面试的时候跟我说这么详细的。那我到你们公司之后怎么就能成长了呢&#xff1f;” “你们这些人最大的问题是出不了方案。 为什么出不了方案&#xff1f; 因为没有养成深度思考问题的习惯。 实现方案、算法、数据迁移、准备数据、…

计算机网络面试题(一)

1、OSI&#xff0c;TCP/IP&#xff0c;五层协议的体系结构&#xff0c;以及各层协议 OSI分层 &#xff08;7层&#xff09;&#xff1a;物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。 TCP/IP分层&#xff08;4层&#xff09;&#xff1a;网络接口 网络层、运…

Ubuntu下安装和配置Apache2

在Ubuntu中安装apache 安装指令&#xff1a;sudo apt-get install apache2 安装结束后&#xff1a; 产生的启动和停止文件是&#xff1a;/etc/init.d/apache2 启动&#xff1a;sudo apache2ctl -k start 停止&#xff1a;sudo apache2ctl -k stop 重新启动&#xff1a;sudo apa…

苹果电脑安装python3密码_mac系统安装Python3初体验

前沿 对于iOS开发不要随便拆卸系统自带的Python,因为有很多 library 还是使用 Python2.7。 1 安装Xcode 1.1 App Store 搜索Xcode 并安装 1.2 安装 Xcode command line tool 1.2.1 打开命令行terminal工具 control space 输入terminal 回车 1.2.2 安装Xcode command line tool…

【IBM Tivoli Identity Manager 学习文档】3 系统部署

作者&#xff1a;gnuhpc 出处&#xff1a;http://www.cnblogs.com/gnuhpc/ ITIM 5.0 单服务器配置和部署。 部署ITIM之前要对其组件进行部署&#xff1a; IBM DB2 Enterprise 9.1 with FP2 IBM WebSphere Application Server 6.1 with FP9 IBM Tivoli Directory Server 6.2 IB…

数据结构Java版之红黑树(八)

红黑树是一种自动平衡的二叉查找树&#xff0c;因为存在红黑规则&#xff0c;所以有效的防止了二叉树退化成了链表&#xff0c;且查找和删除的速度都很快&#xff0c;时间复杂度为log(n)。 什么是红黑规则&#xff1f; 1.根节点必须是黑色的。 2.节点颜色要么是红要么是黑。 3.…

你真的了解Grid布局吗?

Grid网格布局 概述&#xff1a;Grid将容器划分为一个个网格&#xff0c;通过任意组合不同的网格&#xff0c;做出你想想要的布局 Grid与flex布局相似&#xff0c;将整个Grid分为了容器与子项&#xff08;格子&#xff09; Grid容器的三个重要的概念&#xff1a; 行和列单元格网…

webform里的验证控件

1.非空验证控件&#xff1a;RequireFieldValidator &#xff1b;2.数据比较验证&#xff1a;CompareValidator &#xff1b;3.数据范围验证&#xff1a;RangeValidator &#xff1b;4.正则表达式验证&#xff1a;RegularExpressionValidator &#xff1b;5.自定义条件验证&…

hash是线程安全的吗?怎么解决?_这次进程、线程、多线程和线程安全问题,一次性帮你全解决了...

1. 什么是进程一个软件&#xff0c;在操作系统中运行时&#xff0c;我们称其为进程。进程是操作系统分配资源的最小单元&#xff0c;线程是操作系统调度的最小单元。2. 什么是线程在一个进程中&#xff0c;每个独立的功能都需要独立的去运行&#xff0c;这时又需要把当前这个进…

WinXP不能共享Win7的打印机的解决方法

现在很多企业里存在着WinXP和Win7混用&#xff0c;WinXP不能正常共享Win7的文件和打印机&#xff0c;经过设置发现Win7可以Ping通Winxp并且也可以发现WinXP的共享文件&#xff0c;可是WinXP却不能共享Win7的文件和打印机&#xff0c;看了一下相关资料后简单设置就解决了这个问题…

第三阶段 10_JavaWeb基础_

因为要准备接本&#xff0c;不一定能够每天更新 转载于:https://www.cnblogs.com/BaiZe258/p/9251075.html

工厂模式(Factory)(转)

先来明确一个问题&#xff0c;那就是有的时候&#xff0c;实例化这个活动不应该总是公开的进行&#xff0c; 也就是不要公开的使用 new 操作符&#xff0c;因为&#xff0c;这样容易造成耦合问题。 我们不应该针对实现编程&#xff0c;但是当我们在使用 new 的时候&#xff0c;…

Asp.net后台创建HTML

为了使HTML界面中的内容能根据数据库中的内容动态显示用户需要的内容&#xff0c;或者根据权限不同要显示同而实现页面内容的动态创建 使用HtmlGenericControl创建HTML标签 引入命名空间: using System.Web.UI.HtmlControls; 更改其属性: hgg_div.Attributes.Add("style&q…

oracle视图(转)

视图的概念 视图是基于一张表或多张表或另外一个视图的逻辑表。视图不同于表&#xff0c;视图本身不包含任何数据。表是实际独立存在的实体&#xff0c;是用于存储数据的基本结构。而视图只是一种定义&#xff0c;对应一个查询语句。视图的数据都来自于某些表&#xff0c;这些…

Redis 事物

redis 事物&#xff1a; Redis 事物的实现&#xff1a; 首先 wath监控键值 myKey开启批量执行 multi&#xff0c;执行命令入列&#xff0c;执行 exec 。如果监控的键值mykey 没有被修改过&#xff0c;则exec 中批量执行的命令成功&#xff0c;否则执行失败。无论执行成功与否&a…