程序架构重要性
很多人尤其是初学者在写代码的时候往往都是想一点写一点,最开始没有一个整体的规划,导致后面代码越写越乱,bug不断。
最终代码跑起来看似没有问题(有可能也真的没有问题),但是系统的可扩展性很差,添加一个功能的时候会浪费大量的时间,甚至导致整个代码的崩溃。
所以,在一个项目开始的时候多花一些时间在代码的架构设计上是十分有必要的。代码架构确定好了之后你会发现敲代码的时候会特别快,并且在后期调试的时候也不会像无头苍蝇一样胡乱找问题。当然,调试也是一门技术。
在学习实时操作系统的过程中,发现实时操作系统框架与个人的业务代码之间的耦合性就非常低,都是只需要将业务代码通过一定的接口函数注册好后就交给操作系统托管了,十分方便。
但是操作系统的调度过于复杂,这里就使用操作系统的思维方式来重构这个时间片轮询框架。实现该框架的完全解耦,用户只需要包含头文件,并且在使用过程中不需要改动已经写好的库文件。
Demo
首先来个demo,该demo是使用电脑开两个线程:一个线程模拟单片机的定时器中断产生时间片轮询个时钟,另一个线程则模拟主函数中一直运行的时间片轮询调度程序。
#include #include #include #include"timeslice.h" //创建5个任务对象 TimesilceTaskObjtask_1,task_2,task_3,task_4,task_5; //具体的任务函数 voidtask1_hdl() { printf(">>task1isrunning...n"); } voidtask2_hdl() { printf(">>task2isrunning...n"); } voidtask3_hdl() { printf(">>task3isrunning...n"); } voidtask4_hdl() { printf(">>task4isrunning...n"); } voidtask5_hdl() { printf(">>task5isrunning...n"); } //初始化任务对象,并且将任务添加到时间片轮询调度中 voidtask_init() { timeslice_task_init( task_1,task1_hdl,1,10); timeslice_task_init( task_2,task2_hdl,2,20); timeslice_task_init( task_3,task3_hdl,3,30); timeslice_task_init( task_4,task4_hdl,4,40); timeslice_task_init( task_5,task5_hdl,5,50); timeslice_task_add( task_1); timeslice_task_add( task_2); timeslice_task_add( task_3); timeslice_task_add( task_4); timeslice_task_add( task_5); } //开两个线程模拟在单片机上的运行过程 voidtimeslice_exec_thread() { while(true) { timeslice_exec(); } } voidtimeslice_tick_thread() { while(true) { timeslice_tick(); Sleep(10); } } intmain() { task_init(); printf(">>tasknum:%dn",timeslice_get_task_num()); printf(">>tasklen:%dn",timeslice_get_task_timeslice_len( task_3)); timeslice_task_del( task_2); printf(">>delettask2n"); printf(">>task2isexist:%dn",timeslice_task_isexist( task_2)); printf(">>tasknum:%dn",timeslice_get_task_num()); timeslice_task_del( task_5);printf(">>delettask5n"); printf(">>tasknum:%dn",timeslice_get_task_num()); printf(">>task3isexist:%dn",timeslice_task_isexist( task_3)); timeslice_task_add( task_2);printf(">>addtask2n"); printf(">>task2isexist:%dn",timeslice_task_isexist( task_2)); timeslice_task_add( task_5);printf(">>addtask5n"); printf(">>tasknum:%dn",timeslice_get_task_num()); printf("nn========timeslicerunning===========n"); std::threadthread_1(timeslice_exec_thread); std::threadthread_2(timeslice_tick_thread); thread_1.join(); thread_2.join(); return0; }
运行结果如下:
由以上例子可见,这个框架使用十分方便,甚至可以完全不知道其原理,仅仅通过几个简单的接口就可以迅速创建任务并加入到时间片轮询的框架中,十分好用。
时间片轮询架构
其实该部分主要使用了面向对象的思维,使用结构体作为对象,并使用结构体指针作为参数传递,这样作可以节省资源,并且有着极高的运行效率。
其中最难的部分是侵入式链表的使用,这种链表在一些操作系统内核中使用十分广泛,这里是参考RT-Thread实时操作系统中的侵入式链表实现。
h文件:
#ifndef_TIMESLICE_H #define_TIMESLICE_H #include"./list.h" typedefenum { TASK_STOP, TASK_RUN }IsTaskRun; typedefstructtimesilce { unsignedintid; void(*task_hdl)(void); IsTaskRunis_run; unsignedinttimer; unsignedinttimeslice_len; ListObjtimeslice_task_list; }TimesilceTaskObj; voidtimeslice_exec(void); voidtimeslice_tick(void); voidtimeslice_task_init(TimesilceTaskObj*obj,void(*task_hdl)(void),unsignedintid,unsignedinttimeslice_len); voidtimeslice_task_add(TimesilceTaskObj*obj); voidtimeslice_task_del(TimesilceTaskObj*obj); unsignedinttimeslice_get_task_timeslice_len(TimesilceTaskObj*obj); unsignedinttimeslice_get_task_num(void); unsignedchartimeslice_task_isexist(TimesilceTaskObj*obj); #endifc文件:
#include"./timeslice.h" staticLIST_HEAD(timeslice_task_list); voidtimeslice_exec() { ListObj*node; TimesilceTaskObj*task; list_for_each(node, timeslice_task_list) { task=list_entry(node,TimesilceTaskObj,timeslice_task_list); if(task->is_run==TASK_RUN) { task->task_hdl(); task->is_run=TASK_STOP; } } } voidtimeslice_tick() { ListObj*node; TimesilceTaskObj*task; list_for_each(node, timeslice_task_list) { task=list_entry(node,TimesilceTaskObj,timeslice_task_list); if(task->timer!=0) { task->timer--; if(task->timer==0) { task->is_run=TASK_RUN; task->timer=task->timeslice_len; } } } } unsignedinttimeslice_get_task_num() { returnlist_len( timeslice_task_list); } voidtimeslice_task_init(TimesilceTaskObj*obj,void(*task_hdl)(void),unsignedintid,unsignedinttimeslice_len) { obj->id=id; obj->is_run=TASK_STOP; obj->task_hdl=task_hdl; obj->timer=timeslice_len; obj->timeslice_len=timeslice_len; } voidtimeslice_task_add(TimesilceTaskObj*obj) { list_insert_before( timeslice_task_list, obj->timeslice_task_list); } voidtimeslice_task_del(TimesilceTaskObj*obj) { if(timeslice_task_isexist(obj)) list_remove( obj->timeslice_task_list); else return; } unsignedchartimeslice_task_isexist(TimesilceTaskObj*obj) { unsignedcharisexist=0; ListObj*node; TimesilceTaskObj*task; list_for_each(node, timeslice_task_list) { task=list_entry(node,TimesilceTaskObj,timeslice_task_list); if(obj->id==task->id) isexist=1; } returnisexist; } unsignedinttimeslice_get_task_timeslice_len(TimesilceTaskObj*obj) { returnobj->timeslice_len; }
底层侵入式双向链表
该链表是linux内核中使用十分广泛,也十分经典,其原理具体可以参考文章:
https://www.cnblogs.com/skywang12345/p/3562146.html
h文件:
#ifndef_LIST_H #define_LIST_H #defineoffset_of(type,member)(unsignedlong) ((type*)0)->member #definecontainer_of(ptr,type,member)((type*)((char*)(ptr)-offset_of(type,member))) typedefstructlist_structure { structlist_structure*next; structlist_structure*prev; }ListObj; #defineLIST_HEAD_INIT(name){ (name), (name)} #defineLIST_HEAD(name)ListObjname=LIST_HEAD_INIT(name) voidlist_init(ListObj*list); voidlist_insert_after(ListObj*list,ListObj*node); voidlist_insert_before(ListObj*list,ListObj*node); voidlist_remove(ListObj*node); intlist_isempty(constListObj*list); unsignedintlist_len(constListObj*list); #definelist_entry(node,type,member) container_of(node,type,member) #definelist_for_each(pos,head) for(pos=(head)->next;pos!=(head);pos=pos->next) #definelist_for_each_safe(pos,n,head) for(pos=(head)->next,n=pos->next;pos!=(head); pos=n,n=pos->next) #endif
c文件:
#include"list.h" voidlist_init(ListObj*list) { list->next=list->prev=list; } voidlist_insert_after(ListObj*list,ListObj*node) { list->next->prev=node; node->next=list->next; list->next=node; node->prev=list; } voidlist_insert_before(ListObj*list,ListObj*node) { list->prev->next=node; node->prev=list->prev; list->prev=node; node->next=list; } voidlist_remove(ListObj*node) { node->next->prev=node->prev; node->prev->next=node->next; node->next=node->prev=node; } intlist_isempty(constListObj*list) { returnlist->next==list; } unsignedintlist_len(constListObj*list) { unsignedintlen=0; constListObj*p=list; while(p->next!=list) { p=p->next; len++; } returnlen; }
到此,一个全新的,完全解耦的,十分方便易用时间片轮询框架完成。
来源:小麦大叔
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理
审核编辑 黄宇
-
单片机
+关注
关注
6035文章
44554浏览量
634653 -
框架
+关注
关注
0文章
403浏览量
17475
发布评论请先 登录
相关推荐
评论