在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运行

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <string.h>
  5 #include <errno.h>
  6 #include <time.h>
  7 #include <pthread.h>
  8
  9 typedef struct condition
 10 {
 11     pthread_mutex_t pmutex;
 12     pthread_cond_t pcond;
 13 }condition_t;
 14
 15 typedef struct task
 16 {
 17     void *(*run)(void *arg);
 18     void *arg;
 19     struct task *next;
 20 }task_t;
 21
 22 typedef struct threadpool
 23 {
 24     condition_t ready;
 25     task_t *first;
 26     task_t *last;
 27     int counter;
 28     int idle;
 29     int max_threads;
 30     int quit;
 31 }threadpool_t;
 32
 33
 34 int condition_init(condition_t *cond)
 35 {
 36     int status;
 37     if((status = pthread_mutex_init(&cond->pmutex,NULL)))//返回0代表初始化成功
 38         return status;
 39     if((status = pthread_cond_init(&cond->pcond,NULL)))
 40         return status;
 41     return 0;
 42 }
 43 int condition_lock(condition_t *cond)
 44 {
 45     return pthread_mutex_lock(&cond -> pmutex);
 46 }
 47 int condition_unlock(condition_t *cond)
 48 {
 49     return pthread_mutex_unlock(&cond -> pmutex);
 50 }
 51 int condition_wait(condition_t *cond)
 52 {
 53     return pthread_cond_wait(&cond -> pcond,&cond -> pmutex);
 54 }
 55 int condition_timewait(condition_t *cond,const struct timespec *abstime)
 56 {
 57     return pthread_cond_timedwait(&cond->pcond,&cond->pmutex,abstime);
 58 }
 59 int condition_signal(condition_t *cond)
 60 {
 61     return pthread_cond_signal(&cond->pcond);
 62 }
 63 int condition_broadcast(condition_t *cond)
 64 {
 65     return pthread_cond_broadcast(&cond -> pcond);
 66 }
 67 int condition_destory(condition_t *cond)
 68 {
 69     int status;
 70     if((status = pthread_mutex_destroy(&cond -> pmutex)))
 71         return status;
 72     if((status = pthread_cond_destroy(&cond -> pcond)))
 73         return status;
 74     return 0;
 75 }
 76
 77
 78 void *thread_routine(void *arg)
 79 {
 80     struct timespec abstime;
 81     int timeout;
 82     printf("thread 0x%0x is starting\n",(int)pthread_self());
 83     threadpool_t *pool = (threadpool_t *)arg;
 84     while(1)
 85     {
 86         timeout = 0;
 87         condition_lock(&pool -> ready);
 88         pool -> idle++;
 89         //等待队列有任务到来或者线程池销毁的通知
 90         while(pool -> first == NULL && !pool -> quit)
 91         {
 92             printf("thread 0x%0x is waiting\n",(int)pthread_self());
 93             clock_gettime(CLOCK_REALTIME,&abstime);
 94             abstime.tv_sec += 2;
 95             int status=condition_timewait(&pool -> ready,&abstime);
 96             if(status == ETIMEDOUT)
 97             {
 98                 printf("thread 0x%0x is wait timed out\n",(int)pthread_self());
 99                 timeout = 1;
100                 break;
101             }
102
103         }
104         //等到到条件,处于工作状态
105         pool -> idle--;
106
107         if(pool -> first != NULL)
108         {
109             task_t *t = pool -> first;
110             pool -> first = t -> next;
111             //需要先解锁,以便添加新任务。其他消费者线程能够进入等待任务。
112             condition_unlock(&pool -> ready);
113             t -> run(t->arg);
114             free(t);
115             condition_lock(&pool -> ready);
116         }
117         //等待线程池销毁的通知
118         if(pool -> quit && pool ->first == NULL)
119         {
120             pool -> counter--;
121             if(pool->counter == 0)
122             {
123                 condition_signal(&pool -> ready);
124             }
125             condition_unlock(&pool->ready);
126             //跳出循环之前要记得解锁
127             break;
128         }
129
130         if(timeout &&pool -> first ==NULL)
131         {
132             pool -> counter--;
133             condition_unlock(&pool->ready);
134             //跳出循环之前要记得解锁
135             break;
136         }
137         condition_unlock(&pool -> ready);
138     }
139
140     printf("thread 0x%0x is exiting\n",(int)pthread_self());
141     return NULL;
142 }
143
144 //初始化
145 void threadpool_init(threadpool_t *pool, int threads)
146 {
147     condition_init(&pool -> ready);
148     pool -> first = NULL;
149     pool -> last = NULL;
150     pool -> counter = 0;
151     pool -> idle = 0;
152     pool -> max_threads = threads;
153     pool -> quit = 0;
154 }
155
156 //加任务
157 void threadpool_add_task(threadpool_t *pool, void *(*run)(void *arg),void *arg)
158 {
159     task_t *newstask = (task_t *)malloc(sizeof(task_t));
160     newstask->run = run;
161     newstask->arg = arg;
162     newstask -> next = NULL;
163
164     condition_lock(&pool -> ready);
165     //将任务添加到对列中
166     if(pool -> first ==NULL)
167     {
168         pool -> first = newstask;
169     }
170     else
171         pool -> last -> next = newstask;
172     pool -> last = newstask;
173     //如果有等待线程,则唤醒其中一个
174     if(pool -> idle > 0)
175     {
176         condition_signal(&pool -> ready);
177     }
178     else if(pool -> counter < pool -> max_threads)
179     {
180         pthread_t tid;
181         pthread_create(&tid,NULL,thread_routine,pool);
182         pool -> counter++;
183     }
184     condition_unlock(&pool -> ready);
185 }
186 //销毁线程池
187 void  threadpool_destory(threadpool_t *pool)
188 {
189
190     if(pool -> quit)
191     {
192         return;
193     }
194     condition_lock(&pool -> ready);
195     pool->quit = 1;
196     if(pool -> counter > 0)
197     {
198         if(pool -> idle > 0)
199             condition_broadcast(&pool->ready);
200
201         while(pool -> counter > 0)
202         {
203             condition_wait(&pool->ready);
204         }
205     }
206     condition_unlock(&pool->ready);
207     condition_destory(&pool -> ready);
208 }
209
210
211 void *mytask(void *arg)
212 {
213     printf("thread 0x%0x is working on task %d\n",(int)pthread_self(),*(int*)arg);
214     sleep(1);
215     free(arg);
216     return NULL;
217 }
218 int main()
219 {
220     threadpool_t pool;
221     threadpool_init(&pool,3);
222
223     int i ;
224     for(i = 0; i < 10; i++)
225     {
226         int *arg = (int *)malloc(sizeof(int));
227         *arg = i;
228         threadpool_add_task(&pool,mytask,arg);
229     }
230
231     sleep(15);//为了等待其他线程结束 当然也可以通过pthread_join来做
232     threadpool_destory(&pool);
233     return 0;
234 }

-->代码下载

    Github

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

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

时间: 2024-10-10 04:54:20

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

在Linux下写一个简单的进度条,用make指令进行编译。

首先建立一个新的文件,touch progress_bar.c 执行该vim progress_bar.c命令,写进度条的程序.写进一个进度条程序: #include<stdio.h> #include<unistd.h> #include<string.h> void progress() { int i = 0; char bar[102]; memset(bar,0,102*sizeof(char)); const char* lable="|/-\\&

怎样在Windows和Linux下写相同的代码

目前,Linux在国内受到了越来越多的业内人士和用户的青睐.相信在不久的将来,在国内为Linux开发 的应用软件将会有很大的增加(这不,金山正在招兵买马移植WPS呢).由于未来将会是Windows和Linux两强鼎立的格局,怎样能够使得开发的软件保持最大的可移植性就成了一个很重要的问题.小弟经过一段时间的摸索,找到了这个问题的圆满解答. 在Linux下,所有的开发工具和库都属于自由软件,可以免费获得并且功能强大.如果这些工具和库都有相应的Windows版,那么我们就能够在Windows和Linu

Linux下模拟一个简易的消息机制

声明 #define MSG_ERROR  -1 #define MSG_SUCCEED 0 #define MSG_TRUE 1 #define MSG_FALSE 0 #define PM_NOREMOVE    0x00 #define PM_REMOVE    0x01 typedef unsigned long  WPARAM; typedef unsigned long  LPARAM; typedef unsigned int UINT; typedef int MSG_BOOL;

Linux下的进程类别(内核线程、轻量级进程和用户进程)以及其创建方式--Linux进程的管理与调度(四)

本文声明 日期 内核版本 架构 作者 GitHub CSDN 2016-05-12 Linux-4.5 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度-之-进程的创建 本文中出现的,内核线程,轻量级进程,用户进程,用户线程等概念,如果不太熟悉, 可以参见 内核线程.轻量级进程.用户线程三种线程概念解惑(线程≠轻量级进程) Linux进程类别 虽然我们在区分Linux进程类别, 但是我还是想说Linux下只有一种类型的进程,那就是task_str

linux 下写python脚本实现自动补全( 我51论坛也有)

以前都是在windows下开发,但是对于玩linux的人来说,能够在linux下实现python脚本的自动补全的话,那是相当不错的,而我一般是使用的vim作为编辑器,且linux一般选择最小化安装,没有图形界面,参考了下网上的很多方法也没有适合自己,最后自己去看代码的帮助来实现了这个功能,废话不说,现在开始代码下载地址:http://vim.sourceforge.net/scripts/download_script.php?src_id=21842 文件名:pydiction-1.2.3.z

如何在Linux下拷贝一个目录呢

cp -af newadmin/movie/.   uploadfile/mallvideo/ 如何在Linux下拷贝一个目录呢?这好像是再简单不过的问题了. 比如要把/home/usera拷贝到/mnt/temp,首先想到的就是 cp -R /home/usera/* /mnt/temp 但是这样有一个问题,/home/usera下的隐藏文件都不会被拷贝,子目录下的隐藏文件倒是会的. 那如何才是正确的方法呢?有人说用-a选项,有人说用find加管道. 其实没这么复杂,Google了之后,学了一

【转载】在Linux下,一个文件也有三种时间,分别是:访问时间、修改时间、状态改动时间

在windows下,一个文件有:创建时间.修改时间.访问时间.而在Linux下,一个文件也有三种时间,分别是:访问时间.修改时间.状态改动时间. 两者有此不同,在Linux下没有创建时间的概念,也就是不能知道文件的建立时间,但如果文件建立后就没有修改过,修改时间=建立时间;如果文件建立后,状态就没有改动过,那么状态改动时间=建立时间;如果文件建立后,没有被读取过,那么访问时间=建立时间,因为不好判断文件是否被改过.读过.其状态是否变过,所以判断文件的建立时间基本上能为不可能. 如何查一个文件的三

linux 下查看一个进程运行路径

在linux下查看进程大家都会想到用 ps -ef|grep XXX 可是看到的不是全路径,怎么看全路径呢? 每个进程启动之后在 /proc下面有一个于pid对应的路径 例如:ps -ef|grep python 显示:oracle    4431  4366  0 18:56 pts/2    00:00:00 python Server.py 4431就是进程号 到/proc/4431下,ls -l 会看到(需要root权限): 总用量 0 -r--r--r--    1 oracle  

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

1. 在linux下,查看一个运行中的程序, 占用了多少内存, 一般的命令有 (1). ps aux: 其中  VSZ(或VSS)列 表示,程序占用了多少虚拟内存. RSS列 表示, 程序占用了多少物理内存. 虚拟内存可以不用考虑,它并不占用实际物理内存. (2). top 命令也可以 其中  VIRT(或VSS)列  表示,程序占用了多少虚拟内存. 同 ps aux 中的 VSZ列 RES列 表示, 程序占用了多少物理内存.同 ps aux 中的RSS列 2.在linux下, 查看当前系统占用