线程池C语言版本源码(Daniel Robbins著,注释及修正归个人)

来源:互联网 发布:全自动风水罗盘软件 编辑:程序博客网 时间:2024/05/21 17:24
queue.h---------------------------------------------------------------------
typedef struct node {
  struct node *next;
} node;
typedef struct queue {
  node *head, *tail;
} queue;
void queue_init(queue *myroot);
void queue_put(queue *myroot, node *mynode);
node *queue_get(queue *myroot);
queue.c---------------------------------------------------------------------
#include <stdio.h>
#include "queue.h"
void queue_init(queue *myroot) {
  myroot->head=NULL;
  myroot->tail=NULL;
}
void queue_put(queue *myroot,node *mynode) {
  mynode->next=NULL;
  if (myroot->tail!=NULL)
    myroot->tail->next=mynode;
  myroot->tail=mynode;
  if (myroot->head==NULL)
    myroot->head=mynode;
}
node *queue_get(queue *myroot) {
  //get from root
  node *mynode;
  mynode=myroot->head;
  if (myroot->head!=NULL)
    myroot->head=myroot->head->next;
  return mynode;
}
debug.h---------------------------------------------------------------------
#define dabort() /
 {  printf("Aborting at line %d in source file %s/n",__LINE__,__FILE__); abort(); }
control.h-------------------------------------------------------------------
#include <pthread.h>
typedef struct data_control {
  pthread_mutex_t mutex;
  pthread_cond_t cond;
  int active;
} data_control;
control.c-------------------------------------------------------------------
#include "control.h"
int control_init(data_control *mycontrol) {
  int mystatus;
  if (pthread_mutex_init(&(mycontrol->mutex),NULL))
    return 1;
  if (pthread_cond_init(&(mycontrol->cond),NULL))
    return 1;
  mycontrol->active=0;
  return 0;
}
int control_destroy(data_control *mycontrol) {
  int mystatus;
  if (pthread_mutex_destroy(&(mycontrol->mutex)))
    return 1;
  if (pthread_cond_destroy(&(mycontrol->cond)))
    return 1;
  mycontrol->active=0;
  return 0;
}
int control_activate(data_control *mycontrol) {
  int mystatus;
  if (pthread_mutex_lock(&(mycontrol->mutex)))
    return 0;
  mycontrol->active=1;
  pthread_mutex_unlock(&(mycontrol->mutex));
  pthread_cond_broadcast(&(mycontrol->cond));
  return 1;
}
int control_deactivate(data_control *mycontrol) {
  int mystatus;
  if (pthread_mutex_lock(&(mycontrol->mutex)))
    return 0;
  mycontrol->active=0;
  pthread_mutex_unlock(&(mycontrol->mutex));
  pthread_cond_broadcast(&(mycontrol->cond));
  return 1;
}
workcrew.c------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include "control.h"
#include "queue.h"
#include "dbug.h"
#define NUM_WORKERS 24
int numthreads;

/*工作序列提供需要多个线程完成的工作任务 */
struct work_queue {
  data_control control;//多线程控制结构体实例
  queue work;//工作序列
} wq;//带有控制结构的任务序列

/* 这里为每个工作任务增加了一个资源值
   通常一个工作节点都会有需要处理的额外数据
   可以理解为参数,多个可使用结构体完成*/
typedef struct work_node {
  struct node *next;
  int jobnum;
} wnode;
/*  清扫线程处理已停下的线程,线程结束
 之前,它将把自己添加进这个链表,因为
 主线程一直在监视这个列表中的变化,然后
 采取适当的动作如唤醒或释放新的中止线程
   */
struct cleanup_queue {
  data_control control;
  queue cleanup;
} cq;
/* I added a thread number (for debugging/instructional purposes) and
   a thread id to the cleanup node.  The cleanup node gets passed to
   the new thread on startup, and just before the thread stops, it
   attaches the cleanup node to the cleanup queue.  The main thread
   monitors the cleanup queue and is the one that performs the
   necessary cleanup. */
typedef struct cleanup_node {
  struct node *next;
  int threadnum;
  pthread_t tid;
} cnode;
void *threadfunc(void *myarg) {
    fflush(stdin);
   printf("I  AM THREADFUNC /n");
  wnode *mywork;
  cnode *mynode;
  mynode=(cnode *) myarg;//线程节点被作为参数传了进来
  pthread_mutex_lock(&wq.control.mutex);
  printf("before  while while wq.control.active = %d  in thread %d /n",wq.control.active,mynode->threadnum);
  fflush(stdout);
  while (wq.control.active)
  {//第一次时为1
 
     while (wq.work.head==NULL && wq.control.active)
  {//虽然任务控制结构状态处于解锁状态,
    //但没有任务节点
    printf(" pthread_cond_wait  in thread %d/n",mynode->threadnum);
   pthread_cond_wait(&wq.control.cond, &wq.control.mutex);
      }
  
 printf(" pthread_cond_not_wait in thread %d/n",mynode->threadnum);
 printf("before  break  wq.control.active = %d  in thread %d /n",wq.control.active,mynode->threadnum);
     if (!wq.control.active) //如果任务控制处于锁定状态
        break;//跳出while(wq.control.active)
        
     //任务控制结构状态处于解锁状态,任务序列头结点不空
     mywork=(wnode *) queue_get(&wq.work);//接任务单
     pthread_mutex_unlock(&wq.control.mutex);//解锁任务控制结构,其他线程可修改
     //只是打印消息,没有处理函数
     printf("Thread number %d processing job %d/n",mynode->threadnum,mywork->jobnum);
     free(mywork);//释放任务节点内存
     pthread_mutex_lock(&wq.control.mutex);//在pthread_cond_wait之前一定要加锁
  }
/*总结:
1.   多线程状态变量和互斥锁的函数调用次序不可颠倒:
       A:   pthread_mutex_lock -->B: pthread_cond_wait --> C: pthread_mutex_unlock
2. 任务完成以后一定要及时释放任务所占用的内存资源
3. 线程自身的收尾合并工作也需要特别注意,可以使用
 状态变量信号相同的方法,也可以使用可分离状态
       */
  printf(" not in while while in thread %d/n",mynode->threadnum);
  pthread_mutex_unlock(&wq.control.mutex);
  pthread_mutex_lock(&cq.control.mutex);
 
  queue_put(&cq.cleanup,(node *) mynode);
 
  pthread_mutex_unlock(&cq.control.mutex);
 
  pthread_cond_signal(&cq.control.cond);
 
  printf("thread %d shutting down.../n",mynode->threadnum);
 
  return NULL;
 
}
 
void join_threads(void) {
  cnode *curnode;
  printf("joining threads.../n");
  while (numthreads) {
   //注意wait函数的调用次序 先锁后等再解
    pthread_mutex_lock(&cq.control.mutex);
    /* 下面的代码睡眠以等待一个新的清除节点
 用于清除一个线程,这一点需要格外小心
 尤其被错误的唤醒,即便我们从函数pthread/-cond/-wait
 中醒来,我们也不应该想当然的认为我们等待
 的状态就真的到来了
       */
    while (cq.cleanup.head==NULL) {
      pthread_cond_wait(&cq.control.cond,&cq.control.mutex);
    }
    /* 条件真的到来时,我们控制住互斥锁并且
 线程队列里面有我们要处理的线程对象首
 先我们将该节点从线程队列里删除然后通
 过存储在线程节点的tid 调用pthread_join 来合并
 该线程,只有等到这个函数返回时才能认为
 该线程已经停止才能调用释放内存函数free()
 来删除节点占用的内存资源,减少需要处理
 线程个数,如果需要就循环该段代码
       */
      curnode = (cnode *) queue_get(&cq.cleanup);//取头结点
      pthread_mutex_unlock(&cq.control.mutex);//解锁
      pthread_join(curnode->tid,NULL);//合并线程
      printf("joined with thread %d/n",curnode->threadnum);//已经合并
 //释放内存
      free(curnode);
      numthreads--;//待合并线程个数自减一次
  }
}

int create_threads(void) {
  int x;
  cnode *curnode;
  for (x=0; x<NUM_WORKERS; x++) {
    curnode=malloc(sizeof(cnode));
    if (!curnode)
      return 1;
    curnode->threadnum=x;
    printf("creat thread %d/n",x);
    if (pthread_create(&curnode->tid, NULL, threadfunc, (void *) curnode))
      return 1;
   
    numthreads++;//全局变量表示线程池中的线程总数
  }
  return 0;
}
void initialize_structs(void) {
  numthreads=0;
  if (control_init(&wq.control))//wq.control.active=0
    dabort();
  queue_init(&wq.work);//头尾置为NULL
  if (control_init(&cq.control)) {//cq.contol.active=0
    control_destroy(&wq.control);
    dabort();
  }
  queue_init(&cq.cleanup); //头尾置为NULL
  control_activate(&wq.control);//wq.control.active=1
}
void cleanup_structs(void) {
 printf("CAN THR CLEANUP_STRUCT BE EXETED  HERE /n");
 
  control_destroy(&cq.control);
  control_destroy(&wq.control);
 
}

int main(void) {
  int x;
  wnode *mywork;
  initialize_structs();
  //初始化完成后阶段性成果为工作,线程池队列都
  //初始化头尾置为NULL 且将wq.control.active=1 cq.con.act=0
  /* 创建线程 */
 
  if (create_threads()) {
    printf("Error starting threads... cleaning up./n");
    join_threads();
    dabort();
  }
printf("this is main thread,numthreads=%d/n",numthreads);
//锁定工作任务队列添加工作项
   pthread_mutex_lock(&wq.control.mutex);
   printf("wq.control.active=%d  in main 215/n",wq.control.active);
  printf("lock wq.control.mutex  in main/n");
    for (x=0; x<16; x++) {
    mywork=malloc(sizeof(wnode));
    if (!mywork) {
      printf("ouch! can't malloc!/n");
      break;
    }
    mywork->jobnum=x;
    queue_put(&wq.work,(node *) mywork);
  }
  //添加完成后解锁并广播工作任务序列已修改
  printf("unlock wq.control.mutex  in main/n");
  pthread_mutex_unlock(&wq.control.mutex);
 
  printf("broadcast wq.control.cond  in main/n");
  pthread_cond_broadcast(&wq.control.cond);
  //等待线程池里的线程把任务一扫而空
  printf("sleeping.../n");
  sleep(2);
 printf("wq.control.active=%d  in main 235/n",wq.control.active);
 //感觉差不多执行完了以后将工作任务序列由激活变为非激活
  printf("deactivating work queue.../n");
  control_deactivate(&wq.control);//wq.control.active=0
  /* 完成对所有线程组成的线程队列的清理工作*/
  printf("wq.control.active=%d  in main 240/n",wq.control.active);
  join_threads();//合并回收所有线程
  cleanup_structs();//释放所有已分配的内存资源防止内存泄漏
  printf("this is last line before return 0/n");
  return 0;
/*
主函数总结:
1. 主函数本身可以作为管理线程
2. 管理线程的执行流程是
A :初始化工作任务和线程队列-->B:创建线程组并置为听等态
--->C:向工作任务组里添加任务激活工作组并广播让线程工作
----->D:休眠等待线程们把工作做完---->E:锁定工作组改变
激活状态并监听合并线程状态信号(此时线程们监听到工作组
激活状态改变信号后跳出傻乎乎的为工作疲于奔命状态开始
发信号广播要求休息合并---->F:主线程收到线程组们的抗议信号
后及时合并线程,防止线程上访,然后做善后事宜,回收内存。
*/
}