在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 ...
随机推荐
- 正则表达式start(),end(),group()方法
一.捕获组的概念 捕获组可以通过从左到右计算其开括号来编号,编号是从1 开始的.例如,在表达式 ((A)(B(C)))中,存在四个这样的组: 1 ((A)(B(C))) 2 (A) 3 ...
- Unity3d UnityEditor EditorWindow 自定义窗体控件
功能:是因为公司的模型组需要一个插件,在MAYA中有很多个复制物体,导出的时候只导出一个,其他相同的物体只导出点的位置信息.这样进入Unity里就是一个物体和N个相同物体的位置点,代码简单但是需要用插 ...
- DB2单个DB重启
db2单个数据库重启 . -------------------------------------------------------------- db2 connect to bpm user ...
- JWS-webservice 与Axis2-webservice的高速实现
在详细介绍这两种框架下的webservice之前,先跟大家交流一下SOA认识,也就是面向服务的体系结构.SOA所要解决的主要问题是在现有基础环境的前提下,通过对现有应用程序和基础结构进行又一次的组合以 ...
- android 44 SQLiteOpenHelper
java package com.sxt.day06_10; import java.util.ArrayList; import com.sxt.day06_10.entity.StudentBea ...
- linux device driver —— 环形缓冲区的实现
还是没有接触到怎么控制硬件,但是在书里看到了一个挺巧妙的环形缓冲区实现. 此环形缓冲区实际为一个大小为bufsize的一维数组,有一个rp的读指针,一个wp的写指针. 在数据满时写进程会等待读进程读取 ...
- 使用CDN加载jQuery类库后备代码
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></ ...
- 把nc v6的源码看懂
看懂nc v6的源码! 碧桂园全部的正式环境的补丁都在我手里. 2015-11-18 2:33 谢谢两位一起努力的兄弟 谢谢超哥,谢谢祈冰哥,谢谢连老师,陈明大哥,谢谢龙哥,珍玉,谢谢廖生哥,谢谢林春 ...
- 单例模式,多种实现方式JAVA
转载请注明出处:http://cantellow.iteye.com/blog/838473 第一种(懒汉,线程不安全): public class Singleton { private stati ...
- 在ec2上创建root用户,并使用root 通过Xshell远程登录aws云服务器
1.根据官网提供的方法登录连接到EC2服务器(官网推荐windows用户使用PUTTY连接) 2. 创建root的密码,输入如下命令: sudo passwd root 3.然后会提示你输入new p ...