程序架構重要性
很多人尤其是初學者在寫代碼的時候往往都是想一點寫一點,最開始沒有一個整體的規劃,導致后面代碼越寫越亂,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; }
到此,一個全新的,完全解耦的,十分方便易用時間片輪詢框架完成。
來源:小麥大叔
免責聲明:本文為轉載文章,轉載此文目的在于傳遞更多信息,版權歸原作者所有。本文所用視頻、圖片、文字如涉及作品版權問題,請聯系小編進行處理
審核編輯 黃宇
-
單片機
+關注
關注
6039文章
44585瀏覽量
636483 -
框架
+關注
關注
0文章
403瀏覽量
17511
發布評論請先 登錄
相關推薦
評論