队列遵循先进先出,那么其实跟链表的尾插就类似的,正好,利用这个特性,可以实现一个简单的等待队列程序软件框架,设计这条队列时,我们依然还是会使用头节点这个东西,但是它在队列中只是存储关键数据,并不是真正意义上的节点,可以将它忽略。
这个等待队列可以设计为以下数据结构:工作者结构+基本队列链式结构
所以可以设计出以下结构体:
//工作者结构 typedef struct __work_st { //工作者编号 int work_serial_num; //工作者执行操作 void (*queue_st)(); }work_st ; //队列结构体实现 typedef struct queue_st { work_st work_queue ; //队列的最大长度 int queue_max_length ; //队列的实际长度 int queue_length ; //队列是否为空的标志 int Null_flag ; //队列是否为满的标志 int Full_flag ; //指向下一个队列节点 struct queue_st *next ; }queue_list;
设计这个数据结构的解析如下:
(1)工作者结构中:work_serial_num用来记录当前工作者的标号,主要用来记录工作者的顺序。
void (*queue_st)();是一个函数指针,这个指针就是所谓的工作,每一个队列节点就是一条工作队列,具体实现什么样的工作可以自己去实现它。
(2)队列结构体:
work_queue就是对应工作者结构,将来核心的执行区域就是它。
queue_max_length是记录队列的最大长度,这个可以在初始化队列头节点的时候给定。
queue_length是记录当前队列的长度,也有引用计数的作用,如果有工作者入队,计数加一,出队,计数减一。
Null_flag是记录当前队列是否为空的标志位。
Full_flag是记录当前队列是否为满的标志位
struct queue_st *next是队列指针域
画一幅图来描述下这个设计的实现:
下面可以来实现这个软件框架模型:
我们需要定义队列的实现函数:
//初始化队列头---->虚设,没有意义,只是为了方便操作 void Init_queue_header(queue_list *header , int queue_length) ; //检查当前队列是否已经满了 ,通过队列满标志和队列最大长度这两个条件同时成立来判断 int Check_queue_full(queue_list *header , int queue_length); //入队--->将要执行的编号和功能函数注册到队列中去 int En_queue(queue_list *header , work_st *workArray) ; //出队--->每个编号对应的功能函数会对应创建一条线程,等待第一条工作队列结束后,才会执行接下来的 //工作。 queue_list *De_queue(queue_list *header) ; //检查当前的队列是否为空,检查的标准是不包括队列头,通过引用计数来计算队列的长度 int Check_queue_null(queue_list *header) ; //获取当前队列的长度,不包括队列头 int Get_queue_Length(queue_list *header) ;下面来实现一下这个程序:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include<pthread.h> #include <Windows.h> #define QUEUE_LEN 10 //工作者结构 typedef struct __work_st { //工作者编号 int work_serial_num; //工作者执行操作 void (*queue_st)(); }work_st ; //队列结构体实现 typedef struct queue_st { work_st work_queue ; //队列的最大长度 int queue_max_length ; //队列的实际长度 int queue_length ; //队列是否为空的标志 int Null_flag ; //队列是否为满的标志 int Full_flag ; //指向下一个队列节点 struct queue_st *next ; }queue_list; //初始化队列头---->虚设,没有意义,只是为了方便操作 void Init_queue_header(queue_list *header , int queue_length) ; //检查当前队列是否已经满了 ,通过队列满标志和队列最大长度这两个条件同时成立来判断 int Check_queue_full(queue_list *header , int queue_length); //入队--->将要执行的编号和功能函数注册到队列中去 int En_queue(queue_list *header , work_st *workArray) ; //出队--->每个编号对应的功能函数会对应创建一条线程,等待第一条工作队列结束后,才会执行接下来的 //工作。 queue_list *De_queue(queue_list *header) ; //检查当前的队列是否为空,检查的标准是不包括队列头,通过引用计数来计算队列的长度 int Check_queue_null(queue_list *header) ; //获取当前队列的长度,不包括队列头 int Get_queue_Length(queue_list *header) ; void print(queue_list *header) { sleep(1); printf("work_serial_num: %d hello kitty.....!\n",header->work_queue.work_serial_num); } void print1(queue_list *header) { sleep(1); printf("work_serial_num: %d hello world.....!\n",header->work_queue.work_serial_num); } //执行工作队列里的任务,每个任务都是一条线程 work_st work_array[] = { {1,print}, {2,print1}, {3,print1}, }; int main(void) { int ret = 0 ; queue_list *queue_node = NULL ; queue_node = malloc(sizeof(queue_list)); //检查队列是否为空队列 if(queue_node == NULL) { printf("队列申请内存为失败!\n"); return -1 ; } printf("queue_node mem:0x%p\n",queue_node); //初始化工作队列头 Init_queue_header(queue_node,3);//QUEUE_LEN //入队 printf("入队:\n"); En_queue(queue_node , &work_array[0]); En_queue(queue_node , &work_array[1]); En_queue(queue_node , &work_array[2]); //获取当前队列的长度 printf("入队后:\n"); ret = Get_queue_Length(queue_node); printf("当前队列的长度:%d\n",ret); printf("----------------------------------------------------------------\n"); queue_node = De_queue(queue_node); printf("出队后:\n"); if(queue_node != NULL) printf("队列不是空的!\n"); return 0 ; } //初始化队列头节点 void Init_queue_header(queue_list *header , int queue_max_length) { queue_list *p = header ; p->work_queue.work_serial_num = 0 ; p->work_queue.queue_st = NULL ; p->queue_length = 0 ; p->queue_max_length = queue_max_length ; //默认初始化队列的时候,保存的NULL_flag是生效的 p->Null_flag = 1 ; //默认是不生效的 p->Full_flag = 0 ; p->next = NULL ; } //检查队列是否为空 //return 1 为空 //return !1 不为空 int Check_queue_null(queue_list *header) { queue_list *p = header ; if(NULL == p) return 1 ; if(p->Null_flag) { p->Null_flag = 1; return p->Null_flag ; } p->Null_flag = 0 ; return p->Full_flag ; } //检查队列是否已经满了 // : 1 为满 int Check_queue_full(queue_list *header , int queue_length) { queue_list *p = header ; if(queue_length == p->Full_flag && queue_length == p->queue_max_length) return 1 ; } //获取当前队列的长度 int Get_queue_Length(queue_list *header) { queue_list *p = header ; if(NULL == p) return -1 ; return p->queue_length ; } //入队 int En_queue(queue_list *header , work_st *workArray) { queue_list *p = header ; queue_list *New = NULL ; New = malloc(sizeof(queue_list)); if(NULL == New){ fprintf(stderr , "分配失败!\n"); return ; } memset(New,0,sizeof(queue_list)); p->queue_length++ ; if(p->queue_length > p->queue_max_length){ printf("队列已满!不能再插入数据\n"); p->Full_flag = 1 ; p->queue_length-- ; return -1; } New->work_queue.work_serial_num = workArray->work_serial_num ; New->work_queue.queue_st = workArray->queue_st ; p->Full_flag = 0 ; p->Null_flag = 0 ; while(NULL != p->next) p = p->next ; New->next = p->next ; p->next = New ; } //出队 queue_list *De_queue(queue_list *header) { queue_list *temp = header; queue_list *p = header ; queue_list *prev ; int count = 0; int queue_num_count = 0 ; int ret ; pthread_t tid ; while(NULL != p->next) { prev = p ; //指向下一个工作 p = p->next ; //每插入一个节点,就相当于创建一条线程来执行对应的工作 ret = pthread_create(&tid , NULL , (void *)p->work_queue.queue_st, p); if(ret < 0){ printf("create work_thread fair!ssssssssssssssssssssssssss\n"); return ; } //等待对应的工作结束 pthread_join(tid,NULL); printf("queue_p mem:0x%p\n",p); //保存当前队列的前一个指针的地址 if(NULL != p->next) { prev->next = p->next ; //出队引用计数减一 header->queue_length-- ; free(p); } else { p->next = NULL ; //出队引用计数减一 header->queue_length-- ; free(p); } printf("queue_len:%d\n",header->queue_length); } //将头节点也删除 free(temp); temp = NULL ; return temp ; }运行结果:
程序仍需优化,预知详情,请看下回分解。。。。