线程池的实现

文章描述了一个基于C语言的线程池系统,使用任务队列实现线程间的协作。队列使用了互斥锁和信号量控制任务的添加和获取,展示了初始化、push任务和pop任务的操作。主线程从文件中读取任务并分发给工作线程执行。
摘要由CSDN通过智能技术生成

背景

理发店有一间工作室,有一名理发师,接待室内有n(n≥1)把椅子。如果没有顾客,理发师就去睡觉;如果理发师在睡觉;有顾客需要理发,则顾客会唤醒他;如果理发师在忙且接待室有空闲椅子,那么此顾客会坐在其中1把空闲的椅子上等待;如果来时所有椅子都有人,那么顾客离去。

head.h

head中存放常用的头文件

#define _HEAD_H    
#include <stdio.h>    
#include <stdlib.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/wait.h>    
#include <string.h>    
#include <pthread.h>    
#include <errno.h>    
#include <arpa/inet.h>    
#include <sys/socket.h>    
#include <fcntl.h>    
#include <sys/epoll.h>    
#include <sys/stat.h>    
#include <sys/mman.h>    
#include <sys/sem.h>    
#include <sys/ioctl.h>    
#include <string.h>    
#include <math.h>    
#include <sys/stat.h>    
#include<time.h>    
#include <pwd.h>    
#include <grp.h>    
#include <ctype.h>    
#include <dirent.h>    
#include<pthread.h>    
#include"thread_pool.h"    
    
#include "color.h"    
#ifdef _D    
#define DBG(fmt, args...) printf(fmt, ##args)//如果可变参数列表没有东西,那么##代表去掉,#代表保留,        
#else    
#define DBG(fmt, args...)    
#endif    

thread_pool.h

线程池的头文件,定义一个队列,队列中中有head,tail,size,total,mutex用于保护数据,cond用于接收信号量,data用来存放数据地址指针

 typedef struct task_queue{    
    int head,tail,size,total;    
      void **data;                                                                              
    pthread_mutex_t mutex;//加锁
    pthread_cond_t cond;//信号    
      
  }task_queue;    
      
  void task_queue_init(struct task_queue *taskQueue,int size);    
  void task_queue_push(struct task_queue *taskQueue,void *data);//将这个空间的东西压入队列中
  void *task_queue_pop(struct task_queue *taskQueue);    
  //线程池    
  void *thread_run(void *arg);//线程处理函数    
      
      

color.h

#define NONE "\033[m"    
    
#define RED "\033[0;32;31m"    
    
#define LIGHT_RED "\033[1;31m"    
    
#define GREEN "\033[0;32;32m"    
    
#define LIGHT_GREEN "\033[1;32m"    
    
#define BLUE "\033[0;32;34m"    
    
#define LIGHT_BLUE "\033[1;34m"    
    
#define DARY_GRAY "\033[1;30m"    
    
#define CYAN "\033[0;36m"    
    
#define LIGHT_CYAN "\033[1;36m"    
    
#define PURPLE "\033[0;35m"    
    
#define LIGHT_PURPLE "\033[1;35m"    
    
#define BROWN "\033[0;33m"    
    
#define YELLOW "\033[1;33m"    
    
#define LIGHT_GRAY "\033[0;37m"    
    
#define WHITE "\033[1;37m"  

 head_pool.cc

任务队列初始化

任务队列中传入多少个任务,total,head,tail全部置0,开辟出size个,大小为void*的data,他的类型为void**所以要转成void**,最后再初始化一下互斥锁。

 void task_queue_init(struct task_queue *taskQueue,int size){
      taskQueue->size=size;//有多少数量
      taskQueue->total=taskQueue->head=taskQueue->tail=0;
     
      taskQueue->data=(void**)calloc(size,sizeof(void *));
      
      pthread_mutex_init(&taskQueue->mutex,NULL);
          return ;
  }

push任务

进入先上锁,如果total==size则说明队列已满,直接返回,如果没满则在尾部插入data,再另total++和tail++,如果tail==size说明队列已经到了末尾的位置,那么就要回到数组头的位置重新开始,最后等待发送信号signal,wait在等待他发送的信号后解锁。

void task_queue_push(struct task_queue *taskQueue,void *data){
          pthread_mutex_lock(&taskQueue->mutex);//共享区,只能允许一个人进去
          if(taskQueue->total==taskQueue->size){
            DBG(YELLOW"<push> : taskQueue is full\n"NONE);
              pthread_mutex_unlock(&taskQueue->mutex);
              return ;
          }
          taskQueue->data[taskQueue->tail]=data;
        DBG(GREEN"<push> : "RED"data"NONE"is pushed!\n");
          taskQueue->tail++;
          taskQueue->total++;
          if(taskQueue->tail==taskQueue->size){
           DBG(YELLOW"<push> taskQueue reach tail!\n"NONE);
              taskQueue->tail=0;
          } 
      pthread_cond_signal(&taskQueue->cond);//等发信号
          pthread_mutex_unlock(&taskQueue->mutex);//解锁
          return;
  }

 pop任务

进行操作先上锁,如果total==0,说明当前没有任务,那么只需要等着发信号就行。

data在数据的头取出,取出后total--,head++,如果head==size,那么则说明head到达了最后一个,就将head指向0号位置,最后解锁,返回给线程池中data数据。

void* task_queue_pop(struct task_queue *taskQueue){
      pthread_mutex_lock(&taskQueue->mutex);         
      while(taskQueue->total==0){//惊群效应
         //拿不到等着就行了,不要用轮询(非阻塞)
          //手册写自动解锁,等待条件变量被发信号,线程执行会被挂起,不占cpu知道条件变量被发信号,  要在入口处被锁住,在返回前会重新锁上
          pthread_cond_wait(&taskQueue->cond,&taskQueue->mutex);
      
      }
      void *data=taskQueue->data[taskQueue->head];              
      DBG(GREEN"<pop> :"BLUE"data"NONE"is poped!\n");
      taskQueue->total--;                                       
      taskQueue->head++;
      if(taskQueue->head==taskQueue->size){
            DBG(YELLOW"<pop> taskQueue reach tail!\n"NONE);
             taskQueue->head=0;
      }
      pthread_mutex_unlock(&taskQueue->mutex);              
      return data;
  }

 总代码

 #include"head.h"
  #include"color.h"
  void task_queue_init(struct task_queue *taskQueue,int size){
      taskQueue->size=size;//有多少数量
      taskQueue->total=taskQueue->head=taskQueue->tail=0;
     
      taskQueue->data=(void**)calloc(size,sizeof(void *));
      
      pthread_mutex_init(&taskQueue->mutex,NULL);
          return ;
  }
  
  void task_queue_push(struct task_queue *taskQueue,void *data){
          pthread_mutex_lock(&taskQueue->mutex);//共享区,只能允许一个人进去
          if(taskQueue->total==taskQueue->size){
            DBG(YELLOW"<push> : taskQueue is full\n"NONE);
              pthread_mutex_unlock(&taskQueue->mutex);
              return ;
          }
          taskQueue->data[taskQueue->tail]=data;
        DBG(GREEN"<push> : "RED"data"NONE"is pushed!\n");
          taskQueue->tail++;
          taskQueue->total++;
          if(taskQueue->tail==taskQueue->size){
           DBG(YELLOW"<push> taskQueue reach tail!\n"NONE);
              taskQueue->tail=0;
          } 
      pthread_cond_signal(&taskQueue->cond);//等发信号
          pthread_mutex_unlock(&taskQueue->mutex);//解锁
          return;
  }
                 
  void* task_queue_pop(struct task_queue *taskQueue){
      pthread_mutex_lock(&taskQueue->mutex);         
      while(taskQueue->total==0){//惊群效应
         //拿不到等着就行了,不要用轮询(非阻塞)
          //手册写自动解锁,等待条件变量被发信号,线程执行会被挂起,不占cpu知道条件变量被发信号,  要在入口处被锁住,在返回前会重新锁上
          pthread_cond_wait(&taskQueue->cond,&taskQueue->mutex);
      
      }
      void *data=taskQueue->data[taskQueue->head];              
      DBG(GREEN"<pop> :"BLUE"data"NONE"is poped!\n");
      taskQueue->total--;                                       
      taskQueue->head++;
      if(taskQueue->head==taskQueue->size){
            DBG(YELLOW"<pop> taskQueue reach tail!\n"NONE);
             taskQueue->head=0;
      }
      pthread_mutex_unlock(&taskQueue->mutex);              
      return data;
  }
  
  void *thread_run(void *arg){                                                                  
      pthread_detach(pthread_self());//线程分离
      struct task_queue *taskQueue=(struct task_queue*)arg;//强转
      while(1){
          void *data=task_queue_pop(taskQueue);
          printf("%s",(char*)data);
      }
  }

 线程池

线程池的作用就是一直取任务队列中的数据,在这用输出来模拟做任务。

void *thread_run(void *arg){                                                                  
      pthread_detach(pthread_self());//线程分离
      struct task_queue *taskQueue=(struct task_queue*)arg;//强转
      while(1){
          void *data=task_queue_pop(taskQueue);
          printf("%s",(char*)data);
      }
  }

1.thread_pool_main.cc

主函数中使用一个文件指针去打开文件做任务,由于本机linux只是单核,那么INS就设置为1

 开辟一个taskQueue的空间,对该taskQueue进行初始化,定义一个buff去存放指针,对线程进行创建初始化,使用fgets去读取并存入buff的位置,使用push函数去将taskqueue的指针存入buff[ind]的位置,再进行push,由于线程是在等待,那么每当线程空闲下来时可以直接插入。

#include"head.h"    
#define INS 1    
#define SIZE 1000    
int main(){    
    FILE *fp;    
    pthread_t tid[INS];    
    char buff[SIZE][1024];    
    struct task_queue *taskQueue=(struct task_queue*)malloc(sizeof(struct task_queue));    
    task_queue_init(taskQueue,SIZE);                                                            
    
    for(int i=0;i<INS;i++){    
        pthread_create(&tid[i],NULL,thread_run,(void *)taskQueue);    
    }    
    
    while(1){    
        if((fp=fopen("./1.thread_pool_main.cc","r"))==NULL){    
            perror("fopen");    
            exit(1);    
        }    
    
        int ind=0;//index    
        while(fgets(buff[ind],1024,fp)!=NULL){    
            task_queue_push(taskQueue,buff[ind]);    
            if(++ind==SIZE)ind=0;    
        usleep(10000);    
        }    
        fclose(fp);    
    }    
    return 0;    
}    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值