-->线程池介绍(大部分来自网络)

   在这个部分,详细的介绍一下线程池的作用以及它的技术背景以及他提供的一些服务等。大部分内容来自我日常生活中在网络中学习到的一些概念性的东西。

-->代码(大约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 ;
}

-->代码下载

    Github

--------------------------------------------------------------------------------------------------------------------------------------

本文是我学习后,一些总结。比较基础,适合新接触Linux编程的人学习。请勿转载。

在Linux下写一个线程池以及线程池的一些用法和注意点的更多相关文章

  1. 在Linux下写一个简单的驱动程序

    本文首先描述了一个可以实际测试运行的驱动实例,然后由此去讨论Linux下驱动模板的要素,以及Linux上应用程序到驱动的执行过程.相信这样由浅入深.由具体实例到抽象理论的描述更容易初学者入手Linux ...

  2. 【转】在Linux下写一个简单的驱动程序

    转自:https://www.cnblogs.com/amanlikethis/p/4914510.html 本文首先描述了一个可以实际测试运行的驱动实例,然后由此去讨论Linux下驱动模板的要素,以 ...

  3. 在Linux下制作一个磁盘文件,在u-boot 阶段对emmc 烧写整个Linux系统方法

    在Linux 下制作一个磁盘文件, 可以给他分区,以及存储文件,然后dd 到SD卡便可启动系统. 在u-boot 下启动后可以读取该文件,直接在u-boot 阶段就可以做烧写操作,省略了进入系统后才进 ...

  4. Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 2 部分: DTrace

    DTrace的原理本系列文章详细地介绍了一个 Linux 下的全新的调式.诊断和性能测量工具 Systemtap 和它所依赖的基础 kprobe 以及促使开发该工具的先驱 DTrace 并给出实际使用 ...

  5. 如何在linux下制作一个windows的可启动u盘?

    如何在linux下制作一个windows的可启动u盘? 情景是这样的,有一个windows10的iso,现在想通过U盘安装,要求即支持UEFI(启动引导器),又支持Legacy(启动引导器),因为有一 ...

  6. Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 3 部分: Systemtap

    Systemtap的原理,Systemtap与DTrace比较,以及安装要求和安装步骤本系列文章详细地介绍了一个Linux下的全新的调式.诊断和性能测量工具Systemtap和它所依赖的基础kprob ...

  7. Linux下的进程类别(内核线程、轻量级进程和用户进程)--Linux进程的管理与调度(四)

    本文中出现的,内核线程,轻量级进程,用户进程,用户线程等概念,如果不太熟悉, 可以参见 内核线程.轻量级进程.用户线程三种线程概念解惑(线程≠轻量级进程) Linux进程类别 虽然我们在区分Linux ...

  8. linux下,一个运行中的程序,究竟占用了多少内存

    linux下,一个运行中的程序,究竟占用了多少内存 1. 在linux下,查看一个运行中的程序, 占用了多少内存, 一般的命令有 (1). ps aux: 其中  VSZ(或VSS)列 表示,程序占用 ...

  9. Linux下配置一个VNC服务器

    在Linux下配置一个VNC服务器,并设置2个用户,要求其中一个用户登录时不需要输入密码. 然后在客户端使用ssh+vncview的方式访问. 1确认vnc安装 2配置vncserver 3测试vnc ...

随机推荐

  1. 385. Mini Parser

    括号题一般都是stack.. 一开始想的是存入STACK的是SRING,然后POP出括号在构建新的NestedInteger放到另一个里面,但是操作起来费时费力. 后来猛然发现其实可以直接吧Neste ...

  2. bzoj 2741 分块+可持久化trie

    多个询问l,r,求所有子区间异或和中最大是多少 强制在线 做法: 分块+可持久化trie 1.对于每块的左端点i,预处理出i到任意一个j,()i,j)间所有子区间异或和中最大为多少,复杂度O(\(n\ ...

  3. java_method_readFile读取文件文本xls

    package cn.com.qmhd.tools; import java.io.FileInputStream; import java.io.FileNotFoundException; imp ...

  4. Doctor NiGONiGO’s multi-core CPU(最小费用最大流模板)

    题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=693 题意:有一个 k 核的处理器和 n 个工作,全部的工作都须要在一个核上处理一个单位的 ...

  5. cflow察看工程函数调用关系+Linux 0.11 内核实验环境

    http://savannah.gnu.org/projects/cflow http://tinylab.org/linux-0.11-lab/ http://ftp.gnu.org/gnu/cfl ...

  6. Java基础知识强化之集合框架笔记39:Set集合之HashSet存储字符串并遍历

    1. HashSet类的概述: (1)不保证set的迭代顺序 (2)特别是它不保证该顺序恒久不变 HashSet底层数据结构是哈希表,哈希表依赖于哈希值存储,通过哈希值来确定元素的位置,  而保证元素 ...

  7. Java集群之session共享解决方案

    随着互联网的日益壮大,网站的pv和uv成线性或者指数倍的增加.单服务器单数据库早已经不能满足实际需求.比如像盛大,淘宝这样的大型网络公司,更是如此.     集群,也就是让一组计算机服务器协同工作,达 ...

  8. 知识点摸清 - - function()——JavaScript 函数名后什么时候加括号,什么时候不

    加括号——调用函数 只要是要调用函数执行的,都必须加括号. 此时,function()实际上等于函数的返回值.(没有返回值也已经执行了函数体内的行为).就是说,只要加括号的,就代表将会执行函数体代码. ...

  9. 在iframe中获取iframe外的对象

    parent.document.getElementById("dom ID"); $($(parent.document.getElementById("video-i ...

  10. JS中escape 方法和C#中的对应

    在项目中遇到js中escape过的json字符串,需要在C#中对应模拟编码,记得原来遇到过这个问题,但是当时没记录下来方案, 于是又搜索了一番,发现别人说的都是HttpUtility.UrlEncod ...