-
线程概念
线程是操作系统能够进行运算调度的最小单位,被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。同一进程的多个线程共享同一地址空间,因此,代码段,数据段都是共享的,只有栈是私有的.
-
相关头文件
-
#include <pthread.h>
在Linux下封装好的线程函数,通过 g++ ***.cpp -lpthread -o xxx 编译,./xxx 运行win下需要安装相关文件,可自行网上搜索。
-
#include <unistd.h>
Unix下开发的标准头文件,相当于windows.h -
#include <errno.h>
用于错误信息 -
#include <signal.h>
pthread_kill函数的头文件,信号相关的函数
-
-
头文件对应的函数
*一些注意事项
*int 返回值默认是0为正确,其他错误或特殊含义(会强调)
*当不为0时打印错误信息需要使用strerror(int ret)将错误信息转成字符串打印
*线程不能调用exit或_exit函数,否则主线程也会结束,但可以调用pthread_exit结束自己
*主线程调用pthread_exit会成为僵尸线程,等待子线程结束后结束线程:
-
int pthread_create(pthread_t * thread,const pthread_arrt_t * arrt,void *(*function)(void *),void *arg);
pthread_t thread: Linux 下为unsigned int,引用,返回线程的id号
pthread_arrt_t *arrt: 线程属性,NULL为默认值
void *(*function)(void *): 新线程将执行的函数对应的函数指针
void *arg: 传入执行函数的唯一参数调用本函数将创建一个新的线程,线程将执行函数function,并将线程的id返回。需注意本函数调用的时候非同步,如果需要同步,请在函数中加条件休眠。线程池不需要。
-
pthread_t pthread_self (void);
返回线程的id号,可能会和create_thread的第一个参数不一样(当创建线程和填写id 号之间被中断时候)目前没有遇到过,就认为创建函数是原子操作吧。虽然是个隐患,但一直找不到很好解决策略,能让在主线程获取子线程id。 -
void pthread_exit (void *retval);
线程退出时候,void *retval返回线程传递出的参数,可以是值或者地址,但不能是线程的局部地址。线程池用不到返回值,因为线程要一直运行执行很多任务,此时可以设为NULL。 -
int pthread_cancel (pthread_t thread);
退出id为thread的线程,成功返回值为-1,即((void *) -1); -
int pthread_join (pthread_t thread,void **retval);
pthread_t: 要回收的线程的id号
void **vetval: 退出线程的返回值
当调用此函数时,当前线程挂起,直到线程号为thread的线程终止。一种使用方法是声明一个void *tret; 每次调用函数的时候传递的参数是线程id号和&tret,当join函数返回时候,也就是当前线程结束挂起状态,线程号为thread的线程终止并返回(void *) 1,则在32位系统中用(int)tret即可得到返回的1(在64位中用(long)tret)。- 当线程通过return返回,*retval存放thread线程函数的返回值void *类型
- 当线程通过pthread_cancel异常终止,*retval存放常量PTHREAD_CANCELD,即((void *) -1)
- 当线程通过自己调用pthread_exit终止,*retval存放传给pthread_exit的参数
-
int pthread_detach (pthread_t thread);
thread: 要被分离的线程id号
调用后,线程的返回值不会保留到pthread_join函数调用,而是直接回收资源,在调用pthread_join会发生错误。用于不关心返回值的线程收尾。
信号:
- pthread_kill(pthread_t thread,int signal);
这里signal取0,用于判断id号为thread的线程是否存活。
锁:
*下面不是函数原型,是函数调用的格式
*条件唤醒必须要在之前抢到锁,因为函数执行是解锁—等待—加锁- int pthread_mutex_init (&pthread_mutex_t,NULL);
初始化互斥锁pthread_mutex_t,正常返回0 - int pthread_cond_init (&pthread_cond_t,NULL);
初始化条件pthread_cond_t,正常返回0 - pthread_mutex_destroy(&pthread_mutex_t);
销毁互斥锁pthread_mutex_t - pthread_cond_destroy(&pthread_cond_t);
销毁条件pthread_cond_t - pthread_mutex_lock (&pthread_mutex_t);
抢互斥锁,保证不会出现两个线程同时访问一个数据,注意必须是同一个锁才可以。 - pthread_mutex_unlock (&pthread_mutex_t);
释放互斥锁,让其他线程使用该数据。 - pthread_cond_wait (&pthread_cond_t,&pthread_mutex_t);
释放互斥锁pthread_mutex_t,线程阻塞等待,直到接收到pthread_cond_t信号,开始唤醒,并抢互斥锁pthread_mutex_t,抢到后执行。 - pthread_cond_timedwait (&pthread_cond_t,&pthread_mutex_t,×pec);
释放互斥锁pthread_mutex_t,线程阻塞等待,直到接收到pthread_cond_t信号或者时间到,开始唤醒,并抢互斥锁pthread_mutex_t,抢到后执行。
如果是因为接收到信号,返回值为0;超时返回值为110;错误为其他返回值。 - pthread_cond_signal (&pthread_cond_t);
发送信号,使得一个等待被唤醒。 - pthread_cond_broadcast (&pthread_cond_t);
发送信号,使得所有等待被唤醒,按抢到互斥锁先后轮流运行。
**pthread_cond_timedwait的使用方法:
-
#define WAIT_BY_TIME(my_cond,my_lock,my_time,my_char) \
do {\
struct timeval now;\
struct timespec outtime;\
gettimeofday(&now,NULL);\
outtime.tv_sec = now.tv_sec + my_time; /*最大等待时间*/\
outtime.tv_nsec = now.tv_usec * 1000;\
/*休眠到该可能要管理的时候*/\
int ret = pthread_cond_timedwait(my_cond,my_lock,&outtime);\
/*解锁---等待信号或时间---加锁*/\
\
if (ret == 0) {\
printf(my_char " wake up by condition.\n");\
} else if (ret == 110) {\
printf(my_char " wake up by timeout.\n");\
} else {\
printf("----------- " my_char " wake up error------------\n");\
}\
}while(0)
- 线程池
-
为什么要使用线程池?
在高并发服务器上,往往需要使用多线程处理的方法来提高及时响应的能力,而线程池就是一个处理多线程很好的工具。在Unix网络编程中,线程与进程用于处理各项分支子功能,我们通常的操作是:接收消息 ==> 消息分类 ==> 线程创建 ==> 传递消息到子线程 ==> 线程分离 ==> 在子线程中执行任务 ==> 任务结束退出;
这种处理方式在一些比较小型的局域网下下已经很足够了,但是在广域网中,很可能会发生服务器同时接收大量的服务请求。在这种情况下,创建与销毁线程都已经成为一种奢侈的开销,特别对于嵌入式服务器来说更应保证内存资源的合理利用;
因此,线程池技术应运而生;线程池允许一个线程可以多次复用,且每次复用的线程内部的消息处理可以不相同,将创建与销毁的开销省去而不必来一个请求开一个线程;
-
线程池的组成
线程池主要由管理者,任务队列和一些线程组成。管理者负责增删线程的数目,让线程数目和任务数目之间有一个动态平衡,任务队列存放尚未执行的任务,线程则负责运行这些任务。 -
线程池的代码实现方式
首先初始化线程池,设置一些核心线程数,最大线程数,任务队列大小等等。将其保存在一个结构体中。并为线程id和任务队列存储创建空间。第一次初始化的时候先创建核心线程和管理者线程,所有的线程均一直运行到pthread_exit或者线程池关闭。工作线程检查任务队列,若为空则等待信号que_not_empty,若接受到信号,且函数抢到锁,则继续运行,判断是需要自己结束自己还是有新的任务来了,分别处理对应的情况。我这里的优化是若处理任务结束,相当于进入空闲状态,即线程数可能会有些多了,可以概率唤醒管理者。
管理者线程每次等待别人的唤醒或者等到时间到达启动,检查线程数是否过多或者任务队列是否过多,删除或增加相应数目的线程。这里增加和删除数目加以优化,以尽可能少反复删除创建线程为目标。因此我采用预估于现实结合的方式,预估是判断任务队列中的任务将有多少在接下来的一段时间内(管理者删除线程前)被线程运行,现实就是当前忙碌和空闲的线程数目。删除线程数目也是一样计算,以此避免一个线程刚刚创建就被删除。
任务添加函数在每次任务到达的时候进行判断,任务队列是否已满,线程池是否关闭,是否需要唤醒管理者等,最后发送信号,唤醒线程处理任务。
线程池关闭函数则是先关闭管理者,在发送广播让所有存活的线程自杀,最后释放线程池的空间。
-
代码的优化
-
管理者部分
1) 我的管理者启动不再依靠时间为唯一的标准,而是主要通过工作线程函数和任务添加函数发送信号来进行控制,这样可以让管理在更加合适的时间启动,节约资源。2)我的管理者增加和删除线程的算法加了优化,原来的代码是固定每次删除和增加线程的数目,靠宏定义来实现。而我的则是基于当前存活的线程数,当前忙碌的线程数,任务队列中的任务数动态的添加或删除不同数目的线程,保证线程数目波动相对稳定,减少刚刚添加或删除的线程又被删除或重新添加的情况。每次确保是确实需要修改线程数目的时候在进行修改。同时又默认线程大多数时候都会有许多任务要执行,因此每次尽可能多的添加线程。
-
工作线程部分
1)增加了一个唤醒管理者的信号,在每次处理完成函数结束任务恢复空闲状态的时候,就有可能会存活的线程过多,需要删除若干个线程,但又不是每次忙完都需要删除,因为有可能线程又开始执行其他任务,而且只有忙碌线程数不足存活线程数一半时才需要调整,因此我设置一个1/3概率触发条件,启动管理者。 -
添加任务部分
1)当添加任务后,任务队列的数目,比设置的最小等待数目的两倍还要多的时候,就意味这线程此时很可能处理不过来了,需要增加线程来满足如此多的任务,两倍的原因是如果设成单倍,很可能被线程运行了一个任务,管理者在看的时候任务数又少了,相当于本不需要唤醒管理者。这样就可以更快的调节线程数目,满足增加的任务。 -
全局优化
1)一个很好的优化是map函数的使用。这主要是为了让线程可视化性更强,毕竟线程id值有些奇怪,原来的代码打印出来的都是一个类似地址的数字,很不好对比这看,而且这样修改还可以帮助我统计一共创建了多少个线程(当然要减一)。
2)关于#define printf //printf,这条语句感觉加不加关系不是非常大,毕竟printf速度也还可以,而且多线程对于输出时间压缩还是不错的。也可能是因为输出比较少,感觉不到?
3)#define WAIT_BY_TIME(my_cond,my_lock,my_time,my_char)这个宏定义简化了很多代码,而且学到了do{…}while(0) 没有分号的使用技巧,这样可以避免写代码的时候因为一条语句不加大括号产生的错误,而且也可以避免使用大括号时分号的问题。
-
-
代码的问题
当然了,这个代码并不是完美的,依然存在这一些我还没有搞明白的问题,比如不管是原来的代码还是我自己写的代码,main函数有很大的限制,代码量如果稍稍加大,比如在main函数内在定义几个变量或者加上几条语句,再或者让指针p指向全局变量i,即int *p = &i; 都会发生段错误或free错误或指针错误。一直没有搞明白是为什么,如果有大佬们知道,欢迎在下面留言评论。对于效率方面,单纯看main函数执行时间上来说。本代码在一些情况下会好于网上的代码,比如当有2000-20000个任务同时到来(不休眠),每个任务有1s或者不休眠的情况下,本代码的算法要好于原来的代码,而对于任务数较少,如200个任务随机休眠后到来的情况,则相差不大,如果任务休眠时间过长或不休眠的时候还会慢于原来代码。
这是因为一方面本代码考量的更多在同时大量任务的情况,创建尽可能多的线程,而任务少的时候创建释放会浪费过多资源,侧重点不同;另一方面,单纯看main函数其实并不代表代码真正的能力,因为main函数为了代码完整性加上了线程池释放部分的时间,而我们说线程池的创建初衷就是为了线程复用,如此频繁的开关线程池消耗是不言而喻的,也不是实际的情况。而本代码的缺陷恰恰在启动很多线程,关闭线程池时释放线程的时间损耗,因此在实际运用当中还是有很好的优势的。
当然了,通过调整MIN_WAIT_TASK和增加线程数目的细节调整也可以使得算法时间消耗降低,本文就不再继续讨论这些情况了。不过可以肯定的是,在不考虑销毁线程池消耗的情况下,本代码还是有很大优势的,因为在动态任务到来的情况下,任务少时关闭线程并不会带来太多效率上的影响。实际测量也是如此。
-
废话不多说了,直接上代码了,毕竟注释也挺详细的。
源代码的参考链接:https://pan.baidu.com/s/1zWuoE3q0KT5TUjmPKTb1lw 密码:pp42
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <signal.h>
#include <map>
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
#define MIN_WAIT_TASK 1
#define ADMIN_WAIT_TIME 5
#define THREAD_WAIT_TIME 10
#define ADD_TASK_WAIT_TIME 20
//#define printf //printf
#define WAIT_BY_TIME(my_cond,my_lock,my_time,my_char) \
do {\
struct timeval now;\
struct timespec outtime;\
gettimeofday(&now,NULL);\
outtime.tv_sec = now.tv_sec + my_time; /*最大等待时间*/\
outtime.tv_nsec = now.tv_usec * 1000;\
/*休眠到该可能要管理的时候*/\
int ret = pthread_cond_timedwait(my_cond,my_lock,&outtime);\
/*解锁---等待信号或时间---加锁*/\
\
if (ret == 0) {\
printf(my_char " wake up by condition.\n");\
} else if (ret == 110) {\
printf(my_char " wake up by timeout.\n");\
} else {\
printf("----------- " my_char " wake up error------------\n");\
}\
}while(0)
int globl_id = 1;
int globl_exit = 0;
map<unsigned long int,int > mp;
struct threadtask_t { //线程任务
void *(*function)(void *); //线程运行的函数指针
void *arg; //函数的唯一参数
};
struct threadpool_t { //线程池
pthread_mutex_t poollock; //线程池锁
pthread_mutex_t threadlock; //线程锁
pthread_cond_t que_not_empty; //线程领取任务,若无则关掉线程
pthread_cond_t que_not_full; //任务队列不满,可以添加
pthread_cond_t start_admin; //用于唤醒admin线程
pthread_t *thread; //线程数组,存放线程id;
pthread_t admin_thread; //管理线程
threadtask_t *task; //任务数组,存放任务函数参数;
//线程池数据
int max_thr; //最大线程数
int min_thr; //最小线程数
int live_thr; //存活线程数
int busy_thr; //工作线程数
int exit_thr; //需要退出线程数
int step; //一次增删线程数
//任务队列数据
int que_head; //队列头
int que_rear; //队列尾
int que_size; //队列元素个数
int que_max_size; //队列最大大小
int shutdown; //线程池状态,0为关闭
};
/*创建线程池*/
threadpool_t *create_threadpool(int min_thr_num, int max_thr_num, int queue_max_size,int step);
/*释放线程池*/
int threadpool_free(threadpool_t *pool);
/*销毁线程池*/
int threadpool_destroy(threadpool_t *pool);
/*管理线程*/
void *admin_thread(void *threadpool);
/*线程是否存在*/
bool is_thread_alive(pthread_t tid);
/*工作线程*/
void *threadpool_thread(void *threadpool);
/*向线程池的任务队列中添加一个任务*/
int threadpool_add_task(threadpool_t *pool, void *(*function)(void *arg), void *arg);
//创建线程池
threadpool_t * create_threadpool (int min_thr_num,int max_thr_num,int max_que_num,int step)
{
//创建线程池模板
threadpool_t *pool = (threadpool_t *)malloc(sizeof (threadpool_t));
if (pool == NULL)
{
printf("cannot create thread pool\n");
return NULL;
}
//初始化线程池
pool->max_thr = max_thr_num;
pool->min_thr = min_thr_num;
pool->live_thr = min_thr_num;
pool->busy_thr = 0;
pool->exit_thr = 0;
pool->step = step;
pool->que_head = 0;
pool->que_rear = 0;
pool->que_size = 0;
pool->que_max_size = max_que_num;
pool->shutdown = 1;
//初始化锁
if (pthread_mutex_init(&(pool->poollock),NULL) != 0||
pthread_mutex_init(&(pool->threadlock),NULL) != 0||
pthread_cond_init(&(pool->que_not_empty),NULL) != 0||
pthread_cond_init(&(pool->que_not_full),NULL) != 0)
{
printf("init lock or condition error\n");
free(pool);
return NULL;
}
//分配线程空间
pool->thread = (pthread_t *)malloc(sizeof (pthread_t) * max_thr_num + 12);
if (pool->thread == NULL)
{
printf("create thread error\n");
free(pool);
return NULL;
}
memset(pool->thread,0,sizeof (pthread_t) * max_thr_num + 12);
//分配任务队列空间
pool->task = (threadtask_t *)malloc(sizeof (threadtask_t) * max_que_num + 12);
if (pool->task == NULL)
{
printf("create task error\n");
free(pool);
return NULL;
}
//启动最小线程数量
for (int i = 0; i < min_thr_num; i++)
{
int ret = pthread_create(&(pool->thread[i]),NULL,threadpool_thread,(void *)pool);
if (ret == 0) {
mp.insert(map<unsigned long int,int >::value_type(pool->thread[i],globl_id++));
printf("init thread %03d...\n",mp[pool->thread[i]]);
} else {
printf("init thread error: %s\n",strerror(ret));
}
}
int ret = pthread_create(&(pool->admin_thread),NULL,admin_thread,(void *)pool);
if (ret == 0) {
printf("init admin 0x%x...\n",(unsigned int)pool->admin_thread);
} else {
printf("init admin error: %s\n",strerror(ret));
}
return pool;
}
/*释放线程池*/
int threadpool_free(threadpool_t *pool)
{
if (pool == NULL)
{
return -1;
}
if (pool->task)
{
free(pool->task);
}
if (pool->thread)
{
free(pool->thread);
pthread_mutex_lock(&(pool->poollock)); /*先锁住再销毁*/
pthread_mutex_destroy(&(pool->poollock));
pthread_mutex_lock(&(pool->threadlock));
pthread_mutex_destroy(&(pool->threadlock));
pthread_cond_destroy(&(pool->que_not_empty));
pthread_cond_destroy(&(pool->que_not_full));
}
free(pool);
pool = NULL;
return 0;
}
/*销毁线程池*/
int threadpool_destroy(threadpool_t *pool)
{
int i;
if (pool == NULL)
{
return -1;
}
pool->shutdown = false;
/*销毁管理者线程*/
pthread_join(pool->admin_thread, NULL);
//通知所有线程去自杀(在自己领任务的过程中)
pthread_cond_broadcast(&(pool->que_not_empty));
/*等待线程结束 先是pthread_exit 然后等待其结束*/
for (i=0; i<pool->live_thr; i++)
{
pthread_join(pool->thread[i], NULL);
}
threadpool_free(pool);
return 0;
}
//工作线程
void *threadpool_thread (void *arg)
{
threadpool_t *pool = (threadpool_t *)arg;
threadtask_t task;
while(true) //线程一直存活,直到自己结束或被cancel,节约反复创建资源
{
pthread_mutex_lock(&(pool->poollock)); //进入临界区,要读取线程池数据
//当没有任务且线程池没有关闭的时候,一直阻塞即可
while(pool->que_size == 0&&pool->shutdown == 1)
{
printf("%03d is waiting for server...\n",mp[pthread_self()]);
WAIT_BY_TIME(&(pool->que_not_empty),&(pool->poollock),THREAD_WAIT_TIME,"thread");
//唤醒!1.需要结束自己;2.有新的任务来了。情况2会退出while循环
if (pool->exit_thr > 0) //需要杀死线程
{
pool->exit_thr--;
if (pool->live_thr > pool->min_thr) //确实需要结束线程
{
printf("%03d is going to exit...\n",mp[pthread_self()]);
pool->live_thr--; //存活线程数减少
pthread_mutex_unlock(&(pool->poollock));
globl_exit++;
pthread_exit(NULL); //线程自己结束自己,不需要返回值
}
}
}
//线程池关闭情况
if (pool->shutdown == 0)
{
printf("%03d is going to exit...\n",mp[pthread_self()]);
pthread_mutex_unlock(&(pool->poollock));
pthread_exit(NULL); //线程自己结束自己,不需要返回值
}
//有任务到来
printf("%03d is start working...\n",mp[pthread_self()]);
//出队(此时依然是加锁状态)
task.function = pool->task[pool->que_head].function;
task.arg = pool->task[pool->que_head].arg;
pool->que_size--;
pool->que_head = (pool->que_head + 1) % pool->que_max_size;
//广播可以添加新的任务了
pthread_cond_broadcast(&(pool->que_not_full));
//此时暂时不需要线程池的数据了
pthread_mutex_unlock(&(pool->poollock));
//对线程加锁,修改忙碌线程数目
pthread_mutex_lock(&(pool->threadlock));
pool->busy_thr++;
pthread_mutex_unlock(&(pool->threadlock));
//执行函数,如果需要返回值在这里自行取出!
(*task.function)(arg);
printf("%03d is end working...\n",mp[pthread_self()]);
//对线程加锁,修改忙碌线程数目
pthread_mutex_lock(&(pool->threadlock));
pool->busy_thr--;
if (rand() % 3 == 0)
pthread_cond_signal(&(pool->start_admin));
pthread_mutex_unlock(&(pool->threadlock));
}
}
//管理线程
void *admin_thread(void *arg)
{
threadpool_t *pool = (threadpool_t *)arg;
printf("admin is running\n");
while(pool->shutdown == 1) //一直存活到线程池关闭
{
pthread_mutex_lock(&(pool->poollock));
WAIT_BY_TIME(&(pool->start_admin),&(pool->poollock),ADMIN_WAIT_TIME,"admin");
//寄存变量
int size = pool->que_size;
int live = pool->live_thr;
pthread_mutex_unlock(&(pool->poollock));
//寄存忙碌线程数目
pthread_mutex_lock(&(pool->threadlock));
int busy = pool->busy_thr;
pthread_mutex_unlock(&(pool->threadlock));
printf("busy_thr: %d; live_thr: %d; que_size: %d\n",busy,live,size);
//变量是定值的不需要加锁哦!
//存活线程过多的情况
if (busy * 2 < live && live > pool->min_thr)
{
pthread_mutex_lock(&(pool->poollock));
int exit = \
pool->exit_thr = min(live - pool->min_thr, (live - busy * 2 - size) / 2 );
pthread_mutex_unlock(&(pool->poollock));
//一次性杀死step个线程
for (int i = 0; i < exit; i++)
{
pthread_cond_signal(&(pool->que_not_empty));
}
}
//任务队列处理不过来的情况
if (size > MIN_WAIT_TASK && live < pool->max_thr)
{
pthread_mutex_lock(&(pool->poollock));
//遍历线程数组,搜索尚未开启的线程,已经添加pool->step个线程后退出
int step = pool->busy_thr * 2 + pool->que_size - pool->live_thr;
printf("%d----------------------------------\n",step);
for (int i = 0,add = 0; i < pool->max_thr && add < step; i++)
{
if (pool->live_thr == pool->max_thr) //优化
{
break;
}
if (pool->thread[i] == 0 || !is_thread_alive(pool->thread[i])) //可以添加线程
{
int ret = pthread_create(&(pool->thread[i]),NULL,threadpool_thread,(void *)pool);
if (ret == 0) {
mp.insert(map<unsigned long int,int >::value_type(pool->thread[i],globl_id++));
printf("create thread %03d...\n",mp[pool->thread[i]]);
add++;
pool->live_thr++;
} else {
printf("create thread error: %s\n",strerror(ret));
}
}
}
pthread_mutex_unlock(&(pool->poollock));
}
}
return NULL;
}
//线程存活判断
bool is_thread_alive(pthread_t tid)
{
int kill_rc = pthread_kill(tid,0); //保留信号,返回线程是否存在
if (kill_rc == ESRCH) {
return false;
} else {
return true;
}
}
//添加任务
int threadpool_add_task (threadpool_t *pool,void *(* function)(void *arg),void *arg)
{
pthread_mutex_lock(&(pool->poollock));
//线程池关闭
if (pool->shutdown == 0)
{
printf("already close the thread pool!\n");
pthread_mutex_unlock(&(pool->poollock));
return -1;
}
//队列已满,启动管理者线程
while (pool->que_size == pool->que_max_size)
{
printf("too many task!!!\n");
pthread_cond_signal(&(pool->start_admin));
WAIT_BY_TIME(&(pool->que_not_full),&(pool->poollock),ADD_TASK_WAIT_TIME,"add task1");
}
//清空队尾的返回值
if (pool->task[pool->que_rear].arg != NULL)
{
free(pool->task[pool->que_rear].arg);
pool->task[pool->que_rear].arg = NULL;
}
//添加任务
pool->task[pool->que_rear].function = function;
pool->task[pool->que_rear].arg = arg;
pool->que_rear = (pool->que_rear + 1) % pool->que_max_size;
pool->que_size ++;
//任务有些多了
if (pool->que_size > MIN_WAIT_TASK * 2)
{
printf("quit bit more task!!!\n");
pthread_cond_signal(&(pool->start_admin));
WAIT_BY_TIME(&(pool->que_not_full),&(pool->poollock),ADD_TASK_WAIT_TIME,"add task2");
}
//唤醒线程
for (int i = 0; i < pool->que_size; i++)
{
pthread_cond_signal(&(pool->que_not_empty));
//WAIT_BY_TIME(&(pool->que_not_full),&(pool->poollock),ADD_TASK_WAIT_TIME,"add task3");
}
pthread_mutex_unlock(&(pool->poollock));
}
//
int i;timeval t_start, t_end;
void* do_work(void *ptr)
{
printf("hello %d\n",i);
//sleep(3);
return NULL;
return ptr;
}
void f()
{
gettimeofday( &t_end, NULL);
cout << (t_end.tv_sec-t_start.tv_sec) +
(t_end.tv_usec-t_start.tv_usec)/1000000.0 <<endl;
}
int main (void)
{
gettimeofday( &t_start, NULL);
threadpool_t *thp = create_threadpool(10, 100, 100,0);
printf("threadpool init ... ... \n");
srand(time(0));
void *p;
for (i = 0;i < 2000; i ++)
{
threadpool_add_task(thp, do_work, (void *)p);
//usleep(rand() % 100000);
}
printf("---------------------exit: %d id: %d--------------------\n",globl_exit,globl_id - 1);
threadpool_destroy(thp);
f();
return 0;
}
写在最后的话:如果你能有兴趣看完这些,那我真的很高兴。毕竟文字代码都很多,也没有什么图片,但确实是三四天的心血,还是希望可以完整的展现出来,希望可以有人认真读一读吧,当然回访的相关留言就不需要了,我也没有时间。怕什么真理无穷,进一寸有一寸欢喜。