在Linux下写一个线程池以及线程池的一些用法和注意点
-->线程池介绍(大部分来自网络)
在这个部分,详细的介绍一下线程池的作用以及它的技术背景以及他提供的一些服务等。大部分内容来自我日常生活中在网络中学习到的一些概念性的东西。
-->代码(大约240行)
测试一下,具体的实现。
-->代码下载
--------------------------------------------------------------------------------------------------------------------------------------
-->线程池介绍
1、技术背景:服务器程序利用线程技术响应客户请求已经司空见惯,但是线程的使用是有待优化和处理的。单线程执行并不是一个高效的方式,这个时候可能就要考虑高并发,多线程等方式。线程池也是线程优化的一种方式。
在面向对象的过程中,对象的创建和销毁是非常占资源的,每创建一个对象都要获取内存资源以及其他一些资源。在Java中更是如此,他要跟踪每一个对象,在它使用完毕的时候,自动的销毁它并垃圾回收。可想而知,运行的速度之慢。这就产生了“池化技术”。
2、线程池如何提高服务器程序的性能?
●T1 = 创建线程
●T2 = 执行线程 包括访问共享数据、线程同步等
●T3 = 销毁线程
●T = T1 + T2 + T3
单线程的情况下,系统花大量的时间再T1、T3阶段。我们要采取最优的措施,减少T1和T3的系统开销。线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目。
假设:一台服务器,每天要处理10万个请求,这时候,我们比较不用线程池的技术和用线程池,他们的区别。
如果没有用线程池的话,那么程序将会用大把的时候来创建这10万个线程,用线程池,我们一般可用的线程数不会大于10万,所以可以大大减小开销。
3、具体工作流程
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。
4、何时不使用线程池线程
● 如果需要使一个任务具有特定优先级
● 如果具有可能会长时间运行(并因此阻塞其他任务)的任务
● 如果需要将线程放置到单线程单元中(线程池中的线程均处于多线程单元中)
● 如果需要永久标识来标识和控制线程,比如想使用专用线程来终止该线程,将其挂起或按名称发现它
5、一般使用线程池的程序的特点
● 需要花费大量的时候,并且请求的时间比较短。
● 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
● 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。
-->代码
为了方便贴出代码,我全部放在一个文件里。运行gcc main.c -o main -lpthread -lrt运行
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <pthread.h> typedef struct condition
{
pthread_mutex_t pmutex;
pthread_cond_t pcond;
}condition_t; typedef struct task
{
void *(*run)(void *arg);
void *arg;
struct task *next;
}task_t; typedef struct threadpool
{
condition_t ready;
task_t *first;
task_t *last;
int counter;
int idle;
int max_threads;
int quit;
}threadpool_t; int condition_init(condition_t *cond)
{
int status;
if((status = pthread_mutex_init(&cond->pmutex,NULL)))//返回0代表初始化成功
return status;
if((status = pthread_cond_init(&cond->pcond,NULL)))
return status;
return ;
}
int condition_lock(condition_t *cond)
{
return pthread_mutex_lock(&cond -> pmutex);
}
int condition_unlock(condition_t *cond)
{
return pthread_mutex_unlock(&cond -> pmutex);
}
int condition_wait(condition_t *cond)
{
return pthread_cond_wait(&cond -> pcond,&cond -> pmutex);
}
int condition_timewait(condition_t *cond,const struct timespec *abstime)
{
return pthread_cond_timedwait(&cond->pcond,&cond->pmutex,abstime);
}
int condition_signal(condition_t *cond)
{
return pthread_cond_signal(&cond->pcond);
}
int condition_broadcast(condition_t *cond)
{
return pthread_cond_broadcast(&cond -> pcond);
}
int condition_destory(condition_t *cond)
{
int status;
if((status = pthread_mutex_destroy(&cond -> pmutex)))
return status;
if((status = pthread_cond_destroy(&cond -> pcond)))
return status;
return ;
} void *thread_routine(void *arg)
{
struct timespec abstime;
int timeout;
printf("thread 0x%0x is starting\n",(int)pthread_self());
threadpool_t *pool = (threadpool_t *)arg;
while()
{
timeout = ;
condition_lock(&pool -> ready);
pool -> idle++;
//等待队列有任务到来或者线程池销毁的通知
while(pool -> first == NULL && !pool -> quit)
{
printf("thread 0x%0x is waiting\n",(int)pthread_self());
clock_gettime(CLOCK_REALTIME,&abstime);
abstime.tv_sec += ;
int status=condition_timewait(&pool -> ready,&abstime);
if(status == ETIMEDOUT)
{
printf("thread 0x%0x is wait timed out\n",(int)pthread_self());
timeout = ;
break;
} }
//等到到条件,处于工作状态
pool -> idle--; if(pool -> first != NULL)
{
task_t *t = pool -> first;
pool -> first = t -> next;
//需要先解锁,以便添加新任务。其他消费者线程能够进入等待任务。
condition_unlock(&pool -> ready);
t -> run(t->arg);
free(t);
condition_lock(&pool -> ready);
}
//等待线程池销毁的通知
if(pool -> quit && pool ->first == NULL)
{
pool -> counter--;
if(pool->counter == )
{
condition_signal(&pool -> ready);
}
condition_unlock(&pool->ready);
//跳出循环之前要记得解锁
break;
} if(timeout &&pool -> first ==NULL)
{
pool -> counter--;
condition_unlock(&pool->ready);
//跳出循环之前要记得解锁
break;
}
condition_unlock(&pool -> ready);
} printf("thread 0x%0x is exiting\n",(int)pthread_self());
return NULL;
} //初始化
void threadpool_init(threadpool_t *pool, int threads)
{
condition_init(&pool -> ready);
pool -> first = NULL;
pool -> last = NULL;
pool -> counter = ;
pool -> idle = ;
pool -> max_threads = threads;
pool -> quit = ;
} //加任务
void threadpool_add_task(threadpool_t *pool, void *(*run)(void *arg),void *arg)
{
task_t *newstask = (task_t *)malloc(sizeof(task_t));
newstask->run = run;
newstask->arg = arg;
newstask -> next = NULL; condition_lock(&pool -> ready);
//将任务添加到对列中
if(pool -> first ==NULL)
{
pool -> first = newstask;
}
else
pool -> last -> next = newstask;
pool -> last = newstask;
//如果有等待线程,则唤醒其中一个
if(pool -> idle > )
{
condition_signal(&pool -> ready);
}
else if(pool -> counter < pool -> max_threads)
{
pthread_t tid;
pthread_create(&tid,NULL,thread_routine,pool);
pool -> counter++;
}
condition_unlock(&pool -> ready);
}
//销毁线程池
void threadpool_destory(threadpool_t *pool)
{ if(pool -> quit)
{
return;
}
condition_lock(&pool -> ready);
pool->quit = ;
if(pool -> counter > )
{
if(pool -> idle > )
condition_broadcast(&pool->ready); while(pool -> counter > )
{
condition_wait(&pool->ready);
}
}
condition_unlock(&pool->ready);
condition_destory(&pool -> ready);
} void *mytask(void *arg)
{
printf("thread 0x%0x is working on task %d\n",(int)pthread_self(),*(int*)arg);
sleep();
free(arg);
return NULL;
}
int main()
{
threadpool_t pool;
threadpool_init(&pool,); int i ;
for(i = ; i < ; i++)
{
int *arg = (int *)malloc(sizeof(int));
*arg = i;
threadpool_add_task(&pool,mytask,arg);
} sleep();//为了等待其他线程结束 当然也可以通过pthread_join来做
threadpool_destory(&pool);
return ;
}
-->代码下载
--------------------------------------------------------------------------------------------------------------------------------------
本文是我学习后,一些总结。比较基础,适合新接触Linux编程的人学习。请勿转载。
在Linux下写一个线程池以及线程池的一些用法和注意点的更多相关文章
- 在Linux下写一个简单的驱动程序
本文首先描述了一个可以实际测试运行的驱动实例,然后由此去讨论Linux下驱动模板的要素,以及Linux上应用程序到驱动的执行过程.相信这样由浅入深.由具体实例到抽象理论的描述更容易初学者入手Linux ...
- 【转】在Linux下写一个简单的驱动程序
转自:https://www.cnblogs.com/amanlikethis/p/4914510.html 本文首先描述了一个可以实际测试运行的驱动实例,然后由此去讨论Linux下驱动模板的要素,以 ...
- 在Linux下制作一个磁盘文件,在u-boot 阶段对emmc 烧写整个Linux系统方法
在Linux 下制作一个磁盘文件, 可以给他分区,以及存储文件,然后dd 到SD卡便可启动系统. 在u-boot 下启动后可以读取该文件,直接在u-boot 阶段就可以做烧写操作,省略了进入系统后才进 ...
- Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 2 部分: DTrace
DTrace的原理本系列文章详细地介绍了一个 Linux 下的全新的调式.诊断和性能测量工具 Systemtap 和它所依赖的基础 kprobe 以及促使开发该工具的先驱 DTrace 并给出实际使用 ...
- 如何在linux下制作一个windows的可启动u盘?
如何在linux下制作一个windows的可启动u盘? 情景是这样的,有一个windows10的iso,现在想通过U盘安装,要求即支持UEFI(启动引导器),又支持Legacy(启动引导器),因为有一 ...
- Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 3 部分: Systemtap
Systemtap的原理,Systemtap与DTrace比较,以及安装要求和安装步骤本系列文章详细地介绍了一个Linux下的全新的调式.诊断和性能测量工具Systemtap和它所依赖的基础kprob ...
- Linux下的进程类别(内核线程、轻量级进程和用户进程)--Linux进程的管理与调度(四)
本文中出现的,内核线程,轻量级进程,用户进程,用户线程等概念,如果不太熟悉, 可以参见 内核线程.轻量级进程.用户线程三种线程概念解惑(线程≠轻量级进程) Linux进程类别 虽然我们在区分Linux ...
- linux下,一个运行中的程序,究竟占用了多少内存
linux下,一个运行中的程序,究竟占用了多少内存 1. 在linux下,查看一个运行中的程序, 占用了多少内存, 一般的命令有 (1). ps aux: 其中 VSZ(或VSS)列 表示,程序占用 ...
- Linux下配置一个VNC服务器
在Linux下配置一个VNC服务器,并设置2个用户,要求其中一个用户登录时不需要输入密码. 然后在客户端使用ssh+vncview的方式访问. 1确认vnc安装 2配置vncserver 3测试vnc ...
随机推荐
- .\Obj\uCOSDemo.axf: Error: L6218E: Undefined symbol LCD_Fast_DrawPoint (refe
这个问题是 没有定义此函数 解决方法是 定义并声明一下 这个函数!!!
- 我眼中的 Oracle 性能优化
恒生技术之眼 作者 林景忠 大家对于一个业务系统的运行关心有如下几个方面:功能性.稳定性.效率.安全性.而一个系统的性能有包含了网络性能.应用性能.中间件性能.数据库性能等等. 今天从数据库性能的角度 ...
- 【Android - MD】之FloatingActionButton的使用
FloatingActionButton(FAB) 是 Android 5.0 新特性--Material Design 中的一个控件,是一种悬浮的按钮. FloatingActionButton 是 ...
- [转]Android UI:看看Google官方自定义带旋转动画的ImageView-----RotateImageView怎么写(附 图片淡入淡出效果)
http://blog.csdn.net/yanzi1225627/article/details/22439119 众所周知,想要让ImageView旋转的话,可以用setRotation()让其围 ...
- 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(14)-系统小结
原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(14)-系统小结 不知不觉已经过了13讲,(本来还要讲多一讲是,数据验证之自定义验证,基于园友还是对权限这 ...
- zedboard--交叉编译Opencv库的生成 分类: shell ubuntu fool_tree的笔记本 ZedBoard OpenCV 2014-11-08 18:57 171人阅读 评论(0) 收藏
Opencv的移植,xzyfeixiang和rainysky的博客. 第一步肯定是下载opencv的源码包 第二步已经做好的交叉编译环境. 第三步下载安装cmake apt-get install ...
- 经典SQL语句大全之提升
二.提升 1.说明:复制表(只复制结构,源表名:a 新表名:b) (Access可用)法一:select * into b from a where 1<>1(仅用于SQlServer)法 ...
- Android 举例说明自己的定义Camera图片和预览,以及前后摄像头切换
如何调用本地图片,并调用系统拍摄的图像上一博文解释(http://blog.csdn.net/a123demi/article/details/40003695)的功能. 而本博文将通过实例实现自己定 ...
- RPM制作
http://blog.csdn.net/justlinux2010/article/details/9905425
- 最近的两个小项目,1:在Vscode里写C/C++
时间过得真快,一眨眼一个多月没更新了,但这一个月我可没偷懒啊,真的是忙.粘上两篇ReadMe勉强凑合一下,保持博客更新是好习惯. VscodeCppDemo Try to develop C/C++ ...