这两天刚好看完linux&c这本书的进程线程部分,学长建议可以用c语言实现一个简单的线程池,也是对线程知识的一个回顾与应用。线程的优点有好多,它是”轻量级的进程”,所需资源少,多线程共享数据空间,线程之间切换速度更快,可以减少服务器的闲置时间等。

那么我们要在往高层次讲它也有一些缺点,比如一个多线程的程序在创建和销毁线程的时候是比较费资源的,举一个例子,我们要是自己是一个普通饭店老板,当顾客来了我们再做饭,那么势必比较慢,这当然会使得顾客感受不好;但是我们要是KFC工作人员,来一个顾客,马上就能为他服务,这是因为我们提前准备好了汉堡。而线程池也正是这个原理,我们提前创建线程,让它们处在等待状态,要是有任务,就激活线程,执行完毕要是没有任务就继续等待。下面是IBM上对线程池背景介绍

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

下面是我实现的代码:我的先城池大小为5,代码中我为它添加了10个任务。

#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<errno.h>
#include<unistd.h> typedef void*(*FUNC)(void* arg); //指向函数的指针,用来指向我的线程函数。
typedef struct _thpool_jobqueue //任务队列
{
FUNC routine; //定义指向线程函数的指针routine
void* arg; //传向线程函数的参数
struct _thpool_jobqueue *next;
}thpool_jobqueue;
typedef struct _thpool_t //线程池
{
int max_thr_num; //线程池的尺寸
int flag; //是否销毁的标志
pthread_t *thr_id; //线程ID指针
pthread_cond_t jobqueue_cond; //条件变量
pthread_mutex_t jobqueue_mutex; //互斥锁
thpool_jobqueue *jobqueue_head; //指向任务队列的指针
}thpool_t;
static thpool_t * thpool = NULL; //全局变量,指向线程池的指针 /*建议:为了结构更清晰,请从main函数开始,然后线程创建函数--->任务添加函数--->线程函数*/ void *thread_routine() //线程函数
{
thpool_jobqueue *work;
while(1)
{
pthread_mutex_lock(&thpool->jobqueue_mutex);
while((thpool->jobqueue_head == NULL) &&( thpool->flag == 0)) //如果此时没有任务,并且不打算销毁线程池
{
pthread_cond_wait(&thpool->jobqueue_cond,&thpool->jobqueue_mutex);// 就让抢到锁的在此等待,其他线程在锁的外边阻塞
}
if(thpool->flag != 0) //每次可以执行的时候都判断下线程池是否要销毁
{
pthread_mutex_unlock(&thpool->jobqueue_mutex);
pthread_exit(0);
}
work = thpool->jobqueue_head; //若不销毁,则将任务添加到任务队列
thpool->jobqueue_head = thpool->jobqueue_head->next; //让任务指针指向下一个
pthread_mutex_unlock(&thpool->jobqueue_mutex);
work->routine(work->arg); //work->routine = routine = func1
free(work);
}
} void thpool_add_task(void*(*routine)(void *),void* arg) //任务添加函数
{
thpool_jobqueue *work,*member; work = (thpool_jobqueue*)malloc(sizeof(thpool_jobqueue)); //准备任务,将添加到任务队列
work->routine = routine;
work->arg = arg;
work->next = NULL;
pthread_mutex_lock(&thpool->jobqueue_mutex); //对任务队列操作必须保证只有一个线程
member = thpool->jobqueue_head;
if(!member)
{
thpool->jobqueue_head = work; //如果此任务是第一个任务
}
else
{
while(member->next != NULL) //如果不是第一个任务就添加到最后
member = member->next;
member->next = work;
}
pthread_cond_signal(&thpool->jobqueue_cond);
pthread_mutex_unlock(&thpool->jobqueue_mutex);
} void thpool_create(int max_thr_num) //线程创建函数
{
int i;
thpool = (thpool_t *)malloc(sizeof(thpool_t));
if(!thpool)
{
perror("malloc thpool error");
}
thpool->flag = 0; //初始化的过程
thpool->max_thr_num = max_thr_num;
thpool->thr_id = (pthread_t*)malloc(max_thr_num*sizeof(pthread_t));
thpool->jobqueue_head = NULL;
pthread_mutex_init(&thpool->jobqueue_mutex,NULL);
pthread_cond_init(&thpool->jobqueue_cond,NULL);
for(i = 0;i < max_thr_num;i++)
{
pthread_create(&thpool->thr_id[i],NULL,thread_routine,NULL); //创建线程的过程
}
}
void thpool_destroy() //销毁线程池
{
printf("线程池正在销毁\n");
int i;
thpool_jobqueue *member;
if(thpool->flag != 0) //先判断一下销毁标志是否已经销毁
{
return;
}
thpool->flag = 1; //将销毁标志至为1,即需要销毁
pthread_mutex_lock(&thpool->jobqueue_mutex);
pthread_cond_broadcast(&thpool->jobqueue_cond); //广播所有线程要销毁的通知
pthread_mutex_unlock(&thpool->jobqueue_mutex);
for(i = 0;i < thpool->max_thr_num;i++)
{
pthread_join(thpool->thr_id[i],NULL); //等待所有线程都结束
}
free(thpool->thr_id); //将所有线程ID释放
while(thpool->jobqueue_head)
{
member = thpool->jobqueue_head;
thpool->jobqueue_head = thpool->jobqueue_head->next;
free(member); //释放每一个任务
}
pthread_mutex_destroy(&thpool->jobqueue_mutex);//销毁锁
pthread_cond_destroy(&thpool->jobqueue_cond); //销毁条件变量
free(thpool); //销毁指向线程池的指针
printf("销毁完成\n"); } void *func1()
{
printf("thread %u is running\n",pthread_self());
sleep(3); //让别的线程有机会抢锁
} int main(int argc,char *argv[])
{
int i; thpool_create(5); //在线程池里创建5个线程
for(i = 0;i < 10;i++)
{
thpool_add_task(func1,NULL);
}
sleep(10);
thpool_destroy();
}
下面是运行结果:
[kiosk@yangbodong 20150805]$ ./a.out
thread 3508193024 is running
thread 3491407616 is running
thread 3499800320 is running
thread 3516585728 is running
thread 3483014912 is running
thread 3491407616 is running
thread 3508193024 is running
thread 3483014912 is running
thread 3516585728 is running
thread 3499800320 is running
线程池正在销毁
销毁完成 从运行结果中的进程号可以看出总共有5个线程在工作,任务分为两次被执行,前五个running是一次,后五个running是一次,最后完成对线程池的销毁。

linux下c语言实现简单----线程池的更多相关文章

  1. C语言实现简单线程池(转-Newerth)

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

  2. linux下C语言实现的内存池【转】

    转自:http://blog.chinaunix.net/uid-28458801-id-4254501.html 操作系统:ubuntu10.04 前言:     在通信过程中,无法知道将会接收到的 ...

  3. Linux下简单线程池的实现

    大多数的网络服务器,包括Web服务器都具有一个特点,就是单位时间内必须处理数目巨大的连接请求,但是处理时间却是比较短的.在传统的多线程服务器模型中是这样实现的:一旦有个服务请求到达,就创建一个新的服务 ...

  4. Linux多线程实践(9) --简单线程池的设计与实现

    线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以 ...

  5. linux下C语言多线程编程实例

    用一个实例.来学习linux下C语言多线程编程实例. 代码目的:通过创建两个线程来实现对一个数的递加.代码: //包含的头文件 #include <pthread.h> #include ...

  6. linux 下C语言学习路线

    UNIX/Linux下C语言的学习路线.一.工具篇“公欲善其事,必先利其器”.编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工 ...

  7. Unix和Linux下C语言学习指南

    转自:http://www.linuxdiyf.com/viewarticle.php?id=174074 Unix和Linux下C语言学习指南 引言 尽管 C 语言问世已近 30 年,但它的魅力仍未 ...

  8. LINUX下C语言编程调用函数、链接头文件以及库文件

    LINUX下C语言编程经常需要链接其他函数,而其他函数一般都放在另外.c文件中,或者打包放在一个库文件里面,我需要在main函数中调用这些函数,主要有如下几种方法: 1.当需要调用函数的个数比较少时, ...

  9. 基于C++11的100行实现简单线程池

    基于C++11的100行实现简单线程池 1 线程池原理 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小, ...

随机推荐

  1. Orchard Core Framework Samples

    解决方案包含内容 多租户应用 一个ASP.NET Core MVC应用程序,它引用模块项目,并为两个启用了不同模块的租户提供支持. 此Web应用程序的主页提供了更多信息,并链接到两个租户和模块端点.租 ...

  2. Jmeter系列(27)- 常用逻辑控制器(6) | 如果(if)控制器If Controller

    如果(if)控制器(If Controller) 在实际工作中,当使用JMeter做性能脚本或者接口脚本时,当遇到需要对不同的条件做不同的操作时,我们可以使用JMeter中if控制器来实现 if控制器 ...

  3. linux 服务器资源 监控工具

    工具一:vmstat(服务端) 一.vmstat选项参数解释 -V:显示vmstat版本信息 -n:只在开始时显示一次各字段名称 -a:显示活跃和非活跃内存 -d:显示各个磁盘相关统计信息 -D:显示 ...

  4. SAP Shared Object 01 (共享对象)

    介绍 共享对象是在共享内存中的一个对象.共享内存是应用服务器中的一个内存区域,可以被应用服务器中的所有程序访问. 在共享对象出现之前,ABAP使用EXPORT 和 IMPORT语句实现内存区域中内容的 ...

  5. 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁的贡献最大 | 百篇博客分析OpenHarmony源码 | v3.05

    百篇博客系列篇.本篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁的贡献最大 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...

  6. P7515-[省选联考 2021A卷]矩阵游戏【差分约束】

    正题 题目链接:https://www.luogu.com.cn/problem/P7515 题目大意 有一个\(n*m\)的矩形\(A\),然后给出一个\((n-1)*(m-1)\)的矩形\(B\) ...

  7. P4755-Beautiful Pair【笛卡尔树,线段树】

    正题 题目链接:https://www.luogu.com.cn/problem/P4755 题目大意 \(n\)个数字的一个序列,求有多少个点对\(i,j\)满足\(a_i\times a_j\le ...

  8. CF755G-PolandBall and Many Other Balls【倍增FFT】

    正题 题目链接:https://www.luogu.com.cn/problem/CF755G 题目大意 \(n\)个东西排成一排,每个组可以选择一个单独的物品或者两个连续的物品,一个物品不同同时在两 ...

  9. Filter和Interceptor

    Filter的使用 拦截user下的所有请求 @WebFilter("/user/*") public class UserFilter implements Filter { @ ...

  10. webpack基本用法及原理(10000+)

    1 webpack是什么 所有工具的出现,都是为了解决特定的问题,那么前端熟悉的webpack是为了解决什么问题呢? 1.1 为什么会出现webpack js模块化: 浏览器认识的语言是HTML,CS ...