一、线程池
一开始就创建多个线程,让它们一直存活。一旦有任务就直接交给线程去执行。线程执行完任务后回到线程池也不销毁。
二、实现
借助第三者来传递任务。发布任务的人不要知道由谁来执行。执行任务的人不要知道谁发布的,第三者就是一个队列。
发布任务的人将任务插到队列(进入队列尾部),线程从队列中取出第一个节点,然后执行任务。任务用函数和参数描述,使用函数指针和一个参数来保存。
#include <sys/queue.h>//Linux库函数里队列的头文件
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h> //多线程
#include <signal.h>
struct node{
void (*task)(void *);//函数指针,保存任务要执行的函数
void *arg; //交给函数执行的参数
SIMPLEQ_ENTRY(node) ent;//用来指向下一个节点
};
//这里直接调用库函数里初始化创建队列
//定义一个队列
SIMPLEQ_HEAD(,node) taskqueue;
//互斥锁用来保护队列的操作
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; //初始化互斥锁
//所有线程都用这个函数
void *thread_fun(void *arg)
{
//查询队列,有节点就拿出来
while(1)
{
if(!SIMPLEQ_EMPTY(&taskqueue))
{
pthread_mutex_lock(&mutex);//上锁
struct node *tmp=SIMPLEQ_FIRST(&taskqueue);//取出一个节点
SIMPLEQ_REMOVE_HEAD(&taskqueue,ent); //从队列中去除
pthread_mutex_unlock(&mutex);//解锁
//把任务拿出来执行
if(tmp->task)
{
tmp->task(tmp->arg);
}
free(tmp);
}
usleep(1);//每次执行完后睡10ms
}
return NULL;
}
//任务
void mytask(void *a)
{
printf("任务执行中,参数是%d\n",(int)a);
int n=(int) a;
char buffer[100]={0};
sprintf(buffer,"mkdir %d", n);
system(buffer);
}
//信号处理函数
void handler(int sig)
{
int i;
static int n=88;
struct node *tmp;
for(i=0;i<1000;i++)
{
tmp=malloc(sizeof(struct node));
tmp->task=mytask;//把要执行的函数赋值给函数指针
tmp->arg=(void *)(n++); //强制转换成指针,指针的值就是n
pthread_mutex_lock(&mutex);//上锁
SIMPLEQ_INSERT_TAIL(&taskqueue,tmp,ent);
pthread_mutex_unlock(&mutex);//解锁
}
}
int main(void)
{
SIMPLEQ_INIT(&taskqueue);
signal(SIGINT,handler);//捕获Ctl+C 发出的SIGINT信号便开始执行
pthread_t thread[50];
int i;
for(i=0;i<50;i++)
{
pthread_create(thread+i,NULL,thread_fun,NULL);
pthread_detach(thread[i]);
}
while(1);
}
按下Ctrl+C后运行结果: