线程之美之线程池

线程池概念?

顾名思义线程池就是很多线程的集合。需要的时候让其中的一些线程来执行任务。

为什么需要线程池?

线程的创建和销毁是需要时间的。尤其对于并发量比较大的服务器,单个任务比较简单的场合下,每次都为新的任务创建线程,任务结束后再销毁线程,这种做法比较不划算。

为了解决这个问题,可以在一开始就创建n个线程。当接到任务时,就将新的任务委派给已存在的n个线程中的几个去执行。这些线程完成任务之后,又会回到等待状态。

线程池的操作:

1.初始化

将线程池结构体的成员进行初始化。

队列初始化

创建n个线程,然后阻塞线程。

线程被唤醒后,从任务队列里取出任务,然后从中找出要执行的函数,以及要带进去的参数,然后执行该函数,任务数量减减。

2.添加任务

将任务添加到待执行的任务队列里。
任务数量加加
然后唤醒线程。

问题:创建一个简单线程池。并且利用该线程池进行文件复制。

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <error.h>
#include <pthread.h>
#include <sys/queue.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>

//线程池中线程总数为50
#define THREADS_TOTAL 50





//定义一个任务结构体
struct _task{
   void *(*task_2_run)(void *); //指向函数的指针
   void *arg;   //该函数的参数

   //另外还要保存下一个任务结构体的地址
   SIMPLEQ_ENTRY(_task) entry;

   //上面的这句替换之后将变成
   // struct {
   //    struct _task *sqe_next;
   //    } entry;

};




//线程池总结构体
struct {
   pthread_mutex_t mutex; //互斥锁
   pthread_cond_t cond;   //条件变量
   pthread_t *thread;   //线程数组的头地址
   SIMPLEQ_HEAD(,_task) taskq_head; //待执行任务的队列
   //经宏定义替换后
   // struct {
   //    struct _task *sqh_first;
   //    struct _task **sqh_last;
   // }taskq_head;
   int tasks; //待执行任务的数量
}pool;


//线程创建需要的函数,所有的线程都运行这个函数
void *taskhandler(void *arg)
{
   printf("thread %u running\n",pthread_self());
   
   while(1)
   {
      //互斥锁上锁
      pthread_mutex_lock(&pool.mutex);
      if(pool.tasks==0)
      {
         pthread_cond_wait(&pool.cond,&pool.mutex);
      }
      //被唤醒后,从任务队列里取出任务,然后执行
      //取出任务
      struct _task *tasktmp=SIMPLEQ_FIRST(&pool.taskq_head);

      if(tasktmp!=NULL)
      {
         //从队列中除去第一个结点
         SIMPLEQ_REMOVE_HEAD(&pool.taskq_head,entry); 

         //将待执行任务数量减1
         if(pool.tasks>0)
            pool.tasks--;
      }
       //互斥锁解锁
      pthread_mutex_unlock(&pool.mutex);     
      
      if(tasktmp!=NULL)
      {
      //直接运行任务,代进结构体里的参数成员
      tasktmp->task_2_run(tasktmp->arg);
      }
   }
}

//将任务加到任务队列里
void pool_addtask(void *(*task_2_add)(void *),void *arg)
{
   //先上锁
   pthread_mutex_lock(&pool.mutex);

   //先构造一个结点
   struct _task *tasktmp=malloc(sizeof(struct _task));
   tasktmp->task_2_run=task_2_add;//将参数中的函数名放入节点
   tasktmp->arg=arg;//将参数中的arg放入节点

   //将节点插入队列的尾部
   SIMPLEQ_INSERT_TAIL(&pool.taskq_head,tasktmp,entry);

   //将待执行任务的数量加1
   pool.tasks++;

   //叫醒线程池中阻塞睡眠的线程
   pthread_cond_signal(&pool.cond);

   pthread_mutex_unlock(&pool.mutex);
}




//线程池初始化
void pool_init(void)
{
   //互斥锁的初始化
   pthread_mutex_init(&pool.mutex,NULL);
   //条件变量的初始化
   pthread_cond_init(&pool.cond,NULL);

   //动态创建pthread_t的数组
   pool.thread=malloc(sizeof(pthread_t)*THREADS_TOTAL);
   //初始化队列
   SIMPLEQ_INIT(&pool.taskq_head);
   //让待执行任务的数量为0
   pool.tasks=0;
   //创建线程
   int i;
   for(i=0;i<THREADS_TOTAL;i++)
   {
      pthread_create(&pool.thread[i],NULL,taskhandler,NULL);
   }
}

//定义拷贝结构体
struct _copy{
   char *addr_dest;//目标地址
   char *addr_sour; //源地址
   int size;  //拷贝的长度
};

//复制任务
void *copytask(void *arg)
{
   struct _copy *tmp=arg;
   printf("dest: %x,source:%x,size:%d\n",tmp->addr_dest,tmp->addr_sour,tmp->size);
   memcpy(tmp->addr_dest,tmp->addr_sour,tmp->size);  
   msync(tmp->addr_dest,512,MS_SYNC);
   
  
}




//argv[1]是源文件的名字,argv[2]是目标文件的名字
int main(int argc,const char *argv[])
{
   if(argc<3)
   {
      printf("用法:./pool 源文件名 目标文件名");
      exit(EXIT_FAILURE);
   }

   pool_init();


   //打开源文件并映射
   int fd=open(argv[1],O_RDONLY);
   if(fd<0)
   {
      perror("open source file");
      exit(EXIT_FAILURE);
   }
   struct stat st;
   fstat(fd,&st); 
   char *addr_s=mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,fd,0);
   if(addr_s==MAP_FAILED)
   {
      perror("map source file");
      exit(EXIT_FAILURE);
   }
   close(fd);

   //创建新文件并映射
   fd=open(argv[2],O_CREAT|O_RDWR|O_TRUNC,666);
   if(fd<0)
   {
      perror("open dest file");
      exit(EXIT_FAILURE);
   }
   ftruncate(fd,st.st_size);
   
   char *addr_d=mmap(NULL,st.st_size,PROT_WRITE|PROT_READ,MAP_SHARED,fd,0);
   if(addr_d==MAP_FAILED)
   {
      perror("map dest file");
      exit(EXIT_FAILURE);
   }
   close(fd);


   int i;
   struct _copy tmp;
   for(i=0;i<st.st_blocks;i++)
   {
      tmp.addr_dest=addr_d+i*512;
      tmp.addr_sour=addr_s+i*512;
      if(st.st_blocks==1)
      {
         tmp.size=st.st_size;
      }
      else if(i<st.st_blocks-1)
      {
         tmp.size=512;
      }
      else
      {
         tmp.size=st.st_size-i*512;
      }
      //将copytask函数以及我们的参数一起传给pool_addtask
      pool_addtask(copytask,&tmp);
   }

   sleep(20);
   //munmap(addr_s,st.st_size);
   //munmap(addr_d,st.st_size);
   while(1);
   return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值