设计一条简单的等待工作队列之软件模型设计与实现(二)
2023-09-27 14:28:47 时间
上节实现了一条最简单的线程等待工作队列。
http://blog.csdn.net/morixinguan/article/details/77758206
但设计还有诸多因素需要考虑和改进,例如以下:
void print(queue_list *header) int count = 0 ; while(1) sleep(1); printf("工作队列 work_serial_num: %d hello kitty.....!\n",header- work_queue.work_serial_num); count++ ; if(count == 10) break ; }在上面一篇文章的代码中,其中一个工作任务出现了sleep的延迟操作,那么一旦工作任务一多,是不是每个工作队列都需要去调用一个sleep函数?那显得很浪费。。。
我们不如在工作结构体中嵌套两个元素,分别是工作延迟的时间设定,以及最终调用延迟func实现延迟,就像设计等待倒计时一样,时间一到,就出队。这个结构体改进如下:
//工作者结构体 typedef struct __work_st //工作者编号 int work_serial_num; //延迟的时间,以s来计算 int sec ; //工作产生的时间延迟(使用sleep函数产生) void (*work_sleep)(); //工作者执行操作 void (*queue_st)(); }work_st ;这样,在外头实现对sleep函数的封装,可以实现如下:
//每一个工作所对应的时间 void work_sleep(queue_list *header) printf("工作线程等待%ds后执行\n",header- work_queue.sec); sleep(header- work_queue.sec); }sec和work_sleep在入队时对当前的节点进行初始化,如果有多个工作任务插入,则往后指向下一个节点,依次类推。这样出队的时候就调用初始化好的每个节点对应的数据,执行等待,后面再执行对应的任务。
在出队的时候设计原来是这样的结构:
while(NULL != p- next) p = p- next ; }这样在出队的时候就会将入队的所有数据全部出队,这样做不是不对。但如果考虑一个问题,要是一次只出一个,那这个接口就不符合设计要求了。所以,我们改进这个接口,让它调用一次的时候,通过判断队列头来出队,一次只出队一个任务,而不是全部出队,当然也可以全部出队,取决于程序逻辑的实现。
改进接口如下:
//逐个出队 //出队 queue_list *De_queue(queue_list *header) int ret ; int count = 0; int queue_length = 0; pthread_t tid ; queue_list *p = header ; queue_list *prev = NULL ; //如果当前节点的下一个节点为空,则返回空 if(header- next == NULL){ free(header); header = NULL ; printf("header mem:0x%p\n",header); return header ; prev = p ; p = p- next ; ret = pthread_create( tid, NULL , (void *)p- work_queue.work_sleep, p); if(ret 0){ printf("create work_thread fair!ssssssssssssssssssssssssss\n"); return ; //等待对应的工作结束 pthread_join(tid,NULL); //每出队一次,就相当于创建一条线程来执行对应的工作 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); //获取队列的长度 queue_length = Get_queue_Length(header); queue_length = queue_length - 1; header- queue_length = queue_length ; printf("当前队列的长度:%d %d\n",queue_length,header- queue_length); prev- next = p- next ; free(p); return prev ;这里设计还要重视一个比较关键的问题,这也是所有初学者不会考虑到的问题,就是内存的分配和释放的问题。
如上程序,如果free(header)后不将header指向NULL,那么header此时是个野指针。那么返回后,在主程序中判断header的时候,它一定不为空。这种问题,想必大学老师在讲课的时候几乎都没有去讲过,所以很多人一直被误导,malloc到的内存,free掉以后指针就为空了,是这样吗?我们可以写个程序测测看:
#include stdio.h #include stdlib.h #define SIZE 10 int main(void) int *p = NULL ; p = malloc(SIZE) ; *p = 100 ; printf("malloc size: %d malloc mem:0x%p %d\n",SIZE,p,*p); free(p); printf("malloc size: %d malloc mem:0x%p\n",SIZE,p); //p = NULL ; printf("malloc size: %d malloc mem:0x%p %d\n",SIZE,p,*p); return 0 ; }运行结果:
看到了吧,mallco后,对p指针简引用赋值,得到的是100,而free后,虽然释放了内存,但简引用指针p的时候却是个随机值,此时它已经成为了一个野指针。
如果我们把p = NULL加上呢?什么样的结果:
运行结果:
很明显,对一个p = NULL的指针简引用,它一定会段错误。
扯多了,接下来看看等待工作队列的改进整体的实现:
#include stdio.h #include stdlib.h #include string.h #include pthread.h #include Windows.h #define QUEUE_LEN 10运行结果:
//初始化队列头---- 虚设,没有意义,只是为了方便操作 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 work_sleep(queue_list *header);
printf("工作队列 work_serial_num: %d hello kitty.....!\n",header- work_queue.work_serial_num); count++ ; if(count == 2) break ; void print1(queue_list *header) int count = 0 ; while(1) printf("工作队列 work_serial_num: %d hello world.....!\n",header- work_queue.work_serial_num); count++ ; if(count == 3) break ;
printf("当前队列的长度:%d\n",ret); printf("----------------------------------------------------------------\n"); while(queue_node) queue_node = De_queue(queue_node); if(queue_node == NULL) printf("节点是空的\n"); else printf("节点不为空!\n"); return 0 ; //每一个工作所对应的时间 void work_sleep(queue_list *header) printf("工作线程等待%ds后执行\n",header- work_queue.sec); sleep(header- work_queue.sec);
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 ; printf("sec :%d\n",workArray- sec); New- work_queue.sec = workArray- sec ; New- work_queue.work_sleep = workArray- work_sleep ; 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) int ret ; int count = 0; int queue_length = 0; pthread_t tid ; queue_list *p = header ; queue_list *prev = NULL ; //如果当前节点的下一个节点为空,则返回空 if(header- next == NULL){ free(header); header = NULL ; printf("header mem:0x%p\n",header); return header ; prev = p ; p = p- next ; ret = pthread_create( tid, NULL , (void *)p- work_queue.work_sleep, p); if(ret 0){ printf("create work_thread fair!ssssssssssssssssssssssssss\n"); return ; //等待对应的工作结束 pthread_join(tid,NULL); //每出队一次,就相当于创建一条线程来执行对应的工作 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); //获取队列的长度 queue_length = Get_queue_Length(header); queue_length = queue_length - 1; header- queue_length = queue_length ; printf("当前队列的长度:%d %d\n",queue_length,header- queue_length); prev- next = p- next ; free(p); return prev ; }
程序还可以继续优化改进,并实现项目应用,且听下回分解。
morixinguan ITGEGE在线教育嵌入式开发讲师。 CSDN博客专家、CSDN-Linux特邀编辑、CSDN博乐、CSDN学院讲师,目前从事嵌入式开发领域,从事与单片机,Linux,android相关的产品开发。
相关文章
- 第十四届蓝桥杯软件类省赛备赛分享帖(Web应用开发组)
- 网络安全-Cisco Packet Tracer Student软件
- 如何用软件质量模型设计测试用例?
- 那些年,追过的开源软件和技术
- 如何使用linux程序mdadm创建软件RAID1软阵列
- 华为2014届校园招聘软件类面试
- 《团队软件过程(修订版)》—第1章1.5节TSPi过程
- 在Ubuntu中添加和删除PPA的软件源
- 使用Duilib开发Windows软件(2)——控件的基本介绍
- 《Power Designer系统分析与建模实战》——第1章 软件建模和 Power Designer 概述
- 一种基于NTC的控温电路及软件实现
- 浅谈软件项目管理环境下的质量管理
- 你不是一个人在战斗——软件项目团队模型
- 勒索病毒有“解药”?法计算机专家发放解毒软件
- 虚拟机总是安装不上?可以试试360软件管家
- 软件测试用例设计实用经验之谈
- Devexpress XAF框架——基本知识及安装软件介绍
- 如何使用CAD看图软件来修改CAD图纸中的文字?
- 3D建模软件中阵列设计功能如何使用?
- CAD软件中怎么沿墙布置设备?