1.进程池

(1)进程池是由服务器预先创建的一组子进程,这些子进程的数目在3-10个之间。进程池中的所有子进程都运行着相同的代码,并具有相同的属性,比如优先级,PGID等等。因为进程池在服务器启动之初就创建好了,所以他们没有打开不必要的文件描述符(从父进程继承而来),也不会错误地使用大块的堆内存(从父进程复制得到)。

(2) 当有新的任务到来时,主进程将通过某种方式选择进程池中的某一个子进程来为之服务。相对于动态创建子进程,选择一个已经存在的子进程的代价明显要小的多。至于主进程选择哪个进程来为新任务服务,则有两种方式:

①主进程使用某种算法主动选择子进程。最简单、最常用的算法是随机算法和Round-Robin(轮流选取)算法,但更优秀、更智能的算法将使任务在各个工作进程中更均匀地分配、从而减轻服务器的整体压力。

②主进程和所有子进程通过一个共享的工作队列来同步,子进程都睡眠在该工作队列上。当有心的任务到来时,主进程将任务添加到工作队列中。这将唤醒正在等待任务的子进程,不过只有一个子进程获得新任务的“接管权”,它可以从工作队列中取出并执行之,而其他子进程将继续睡眠在工作队列上。

当选择好子进程后,主进程还需要使用某种通知机制来告诉目标子进程有新进程需要处理,并传递必要的数据:
在父进程和子进程之间预先建立好一条管道,然后通过该管道来实现所有进程间通信。在父线程和子线程之间传递数据就要简单的多,因为我们可以把这些数据定义全局的,那么他们本身就是被所有线程共享的。

2.线程池

(1)基本功能

线程池提供了一个解决外部大量用户与服务器有限资源的矛盾,它的基本思想就是在程序 开始时就在内存中开辟一些线程, 线程的数目是 固定的,他们独自形成一个类, 屏蔽了对外的操作, 而服务器只需要将数据包交给线程池就可以了。

当有新的客户请求到达时 , 不是新创建一个线程为其服务 , 而是从“池子”中选择一个空闲的线程为新的客户请求服务 ,服务完毕后 , 线程进入空闲线程池中。如果没有线程空闲的话, 就将数据包暂时积累 ,等待线程池内有线程空闲以后再进行处理。通过对多个任务重用已经存在的线程对象 , 降低了对线程对象创建和销毁的开销。当客户请求时 , 线程对象已经存在, 可以提高请求的响应时间 , 从而整体地提高了系统服务的表现。

(2)一个线程池主要包括以下几个组成部分:

①线程管理器:用于创建并管理线程池

②工作线程:线程池中实际执行任务的线程。在初始化线程时会预先创建好固定数目的线程在池中,这些初始化的线程一般处于空闲状态,一般不占用CPU,占用较小的内存空间。

③任务接口:每个任务必须实现的接口,当线程池的任务队列中有可执行任务时,被空闲的工作线程调去执行(线程的闲与忙是通过互斥量实现的,跟前面文章中的设置标志位差不多),把任务抽象出来形成接口,可以做到线程池与具体的任务无关。

④任务队列:用来存放没有处理的任务,提供一种缓冲机制,实现这种结构有好几种方法,常用的是队列,主要运用先进先出原理,另外一种是链表之类的数据结构,可以动态的为它分配内存空间,应用中比较灵活,下文中就是用到的链表。

3.实现一个线程池:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <assert.h>  /*
*线程池里所有运行和等待的任务都是一个CThread_worker
*由于所有任务都在链表里,所以是一个链表结构
*/
typedef struct worker
{  /*回调函数,任务运行时会调用此函数,注意也可声明成其它形式*/  void *(*process) (void *arg);  void *arg;/*回调函数的参数*/  struct worker *next;  } CThread_worker;  /*线程池结构*/
typedef struct
{  pthread_mutex_t queue_lock;  pthread_cond_t queue_ready;  /*链表结构,线程池中所有等待任务*/  CThread_worker *queue_head;  /*是否销毁线程池*/  int shutdown;  pthread_t *threadid;  /*线程池中允许的活动线程数目*/  int max_thread_num;  /*当前等待队列的任务数目*/  int cur_queue_size;  } CThread_pool;  int pool_add_worker (void *(*process) (void *arg), void *arg);
void *thread_routine (void *arg);  //share resource
static CThread_pool *pool = NULL;
void  pool_init (int max_thread_num)
{  pool = (CThread_pool *) malloc (sizeof (CThread_pool));  pthread_mutex_init (&(pool->queue_lock), NULL);  pthread_cond_init (&(pool->queue_ready), NULL);  pool->queue_head = NULL;  pool->max_thread_num = max_thread_num;  pool->cur_queue_size = 0;  pool->shutdown = 0;  pool->threadid = (pthread_t *) malloc (max_thread_num * sizeof (pthread_t));  int i = 0;  for (i = 0; i < max_thread_num; i++)  {   pthread_create (&(pool->threadid[i]), NULL, thread_routine,NULL);  }
}  /*向线程池中加入任务*/
int  pool_add_worker (void *(*process) (void *arg), void *arg)
{  /*构造一个新任务*/  CThread_worker *newworker = (CThread_worker *) malloc (sizeof (CThread_worker));  newworker->process = process;  newworker->arg = arg;  newworker->next = NULL;/*别忘置空*/  pthread_mutex_lock (&(pool->queue_lock));  /*将任务加入到等待队列中*/  CThread_worker *member = pool->queue_head;  if (member != NULL)  {  while (member->next != NULL)  member = member->next;  member->next = newworker;  }  else  {  pool->queue_head = newworker;  }  assert (pool->queue_head != NULL);  pool->cur_queue_size++;  pthread_mutex_unlock (&(pool->queue_lock));  /*好了,等待队列中有任务了,唤醒一个等待线程; 注意如果所有线程都在忙碌,这句没有任何作用*/  pthread_cond_signal (&(pool->queue_ready));  return 0;
}  /*销毁线程池,等待队列中的任务不会再被执行,但是正在运行的线程会一直
把任务运行完后再退出*/
int  pool_destroy ()
{  if (pool->shutdown)  return -1;/*防止两次调用*/  pool->shutdown = 1;  /*唤醒所有等待线程,线程池要销毁了*/  pthread_cond_broadcast (&(pool->queue_ready));  /*阻塞等待线程退出,否则就成僵尸了*/  int i;  for (i = 0; i < pool->max_thread_num; i++)  pthread_join (pool->threadid[i], NULL);  free (pool->threadid);  /*销毁等待队列*/  CThread_worker *head = NULL;  while (pool->queue_head != NULL)  {  head = pool->queue_head;  pool->queue_head = pool->queue_head->next;  free (head);  }  /*条件变量和互斥量也别忘了销毁*/  pthread_mutex_destroy(&(pool->queue_lock));  pthread_cond_destroy(&(pool->queue_ready));  free (pool);  /*销毁后指针置空是个好习惯*/  pool=NULL;  return 0;
}  void *thread_routine (void *arg)
{  printf ("starting thread 0x%x\n", pthread_self ());  while (1)  {  pthread_mutex_lock (&(pool->queue_lock));  /*如果等待队列为0并且不销毁线程池,则处于阻塞状态; 注意 pthread_cond_wait是一个原子操作,等待前会解锁,唤醒后会加锁*/  while (pool->cur_queue_size == 0 && !pool->shutdown)  {  printf ("thread 0x%x is waiting\n", pthread_self ());  pthread_cond_wait (&(pool->queue_ready), &(pool->queue_lock));  }  /*线程池要销毁了*/  if (pool->shutdown)  {  /*遇到break,continue,return等跳转语句,千万不要忘记先解锁*/  pthread_mutex_unlock (&(pool->queue_lock));  printf ("thread 0x%x will exit\n", pthread_self ());  pthread_exit (NULL);  }  printf ("thread 0x%x is starting to work\n", pthread_self ());  /*assert是调试的好帮手*/  assert (pool->cur_queue_size != 0);  assert (pool->queue_head != NULL);  /*等待队列长度减去1,并取出链表中的头元素*/  pool->cur_queue_size--;  CThread_worker *worker = pool->queue_head;  pool->queue_head = worker->next;  pthread_mutex_unlock (&(pool->queue_lock));  /*调用回调函数,执行任务*/  (*(worker->process)) (worker->arg);  free (worker);  worker = NULL;  }  /*这一句应该是不可达的*/  pthread_exit (NULL);
}  //    下面是测试代码  void *myprocess (void *arg)
{  printf ("threadid is 0x%x, working on task %d\n", pthread_self (),*(int *) arg);  sleep (1);/*休息一秒,延长任务的执行时间*/  return NULL;
}  int  main (int argc, char **argv)
{  pool_init (3);/*线程池中最多三个活动线程*/  /*连续向池中投入10个任务*/  int *workingnum = (int *) malloc (sizeof (int) * 10);  int i;  for (i = 0; i < 10; i++)  {  workingnum[i] = i;  pool_add_worker (myprocess, &workingnum[i]);  }  /*等待所有任务完成*/  sleep (5);  /*销毁线程池*/  pool_destroy ();  free (workingnum);  return 0;
}

结果如图:

调研结果来源于:
http://blog.csdn.net/al_xin/article/details/39258067
http://blog.csdn.net/hubi0952/article/details/8045094

Linux进程池、线程池调研相关推荐

  1. python多线程队列和池_Python3 从零单排28_线程队列进程池线程池

    1.线程队列 线程队列有三种:先进先出,后进先出,按优先级进出,具体如下: 1 importqueue2 3 #先进先出 4 q = queue.Queue(3)5 6 q.put(1)7 q.put ...

  2. 【Linux练习生】线程池

    本节知识所需代码已同步到gitee-> https://gitee.com/ZMZZZhao/linux-git/tree/master/thread_pool 本文收录于专栏:Linux 关注 ...

  3. Linux下通用线程池的创建与使用

    Linux下通用线程池的创建与使用 本文给出了一个通用的线程池框架,该框架将与线程执行相关的任务进行了高层次的抽象,使之与具体的执行任务无关.另外该线程池具有动态伸缩性,它能根据执行任务的轻重自动调整 ...

  4. 【C++学习】 基于Linux/C++简单线程池的实现

    [C++学习] 基于Linux/C++简单线程池的实现 转载自:https://www.cnblogs.com/alwayswangzi/p/7138154.html 我们知道Java语言对于多线程的 ...

  5. 递归锁、信号量、GIL锁、基于多线程的socket通信和进程池线程池

    递归锁.信号量.GIL锁.基于多线程的socket通信和进程池线程池 递归锁 死锁现象:是指两个或两个以上的进程和线程因抢夺计算机资源而产生的一种互相等待的现象 from threading impo ...

  6. 学习笔记(33):Python网络编程并发编程-进程池线程池

    立即学习:https://edu.csdn.net/course/play/24458/296451?utm_source=blogtoedu 进程池与线程池: 一般应用在网站上,进程池或线程池最大的 ...

  7. python 协程池gevent.pool_进程池\线程池,协程,gevent

    目录 1. 进程池与线程池 2. 协程 3. gevent 4. 单线程下实现并发的套接字通信 首先写一个基于多线程的套接字 服务端: from socket import * from thread ...

  8. python并发编程-进程池线程池-协程-I/O模型-04

    目录 进程池线程池的使用***** 进程池/线程池的创建和提交回调 验证复用池子里的线程或进程 异步回调机制 通过闭包给回调函数添加额外参数(扩展) 协程*** 概念回顾(协程这里再理一下) 如何实现 ...

  9. python线程池并发_python 并发编程多线程之进程池/线程池

    一.验证GIL锁的存在 Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行.虽然 Python 解释器中可以"运行"多个线程,但在任意时刻只有一个线程在解释器中运行 ...

  10. Linux进程与线程的区别 详细总结(面试经验总结)

    首先,简要了解一下进程和线程.对于操作系统而言,进程是核心之核心,整个现代操作系统的根本,就是以进程为单位在执行任务.系统的管理架构也是基于进程层面的.在按下电源键之后,计算机就开始了复杂的启动过程, ...

最新文章

  1. Direct2D介绍
  2. linux离线安装ftp_安装Kali Linux之后要做的前10件事
  3. 【数据结构与算法】之深入解析“路径总和”的求解思路与算法示例
  4. ES5-拓展 箭头函数的this、this的优先级
  5. pythonsocket自动化教程_Python 的 Socket 编程教程
  6. python变量域名_想尝试使用python进行域名分析,可是没有接触过python,想请教请教。...
  7. 你身边有创业失败导致负债累累的案例吗
  8. Android中Adapter之BaseAdapter使用
  9. web资源优化-图片篇(一)
  10. Python库(x)纯小学生(我)自制
  11. 平果手机桌面计算机,苹果手机怎么做老系统文件夹-苹果手机桌面怎么建文件夹...
  12. Python实现群发邮件
  13. deepin20如何换源_Deepin更换镜像源
  14. (附源码)Springboot 点餐系统 毕业设计 100908
  15. 【新人入门】HTML——前端纯小白新手入门
  16. 如何学习SQL (转)
  17. 解决Android接入服务器NanoHttpd响应慢的问题
  18. 【观察】纯公有云+全场景SaaS服务,用友YonSuite领跑背后的“制胜秘诀”
  19. c++ 制作五子棋游戏
  20. Freemarker生成HTML静态页面

热门文章

  1. php多线程采集,php浏览器模拟:用于多线程处理的curl_multi一族函数使用介绍
  2. 查理·芒格提炼的9个思维模型
  3. 在世界读书日之后,重温与好书相遇的时光 | O'Reilly赠书活动
  4. python自学行吗知乎_怎么自学python,大概要多久?
  5. input type=button与asp:button的区别,以及runat=server的作用
  6. 深度学习基础--输出层的神经元数应该与分类数匹配(分类数大于等于2)则是一个监督学习任务,对吗?
  7. WPS中文档横线的问题
  8. UG二次开发装配篇 添加/拖动/删除组件方法的实现
  9. XDOC 在线word文档表格预览
  10. 公司企业邮箱账号格式怎么填?