程序架構(gòu)重要性
很多人尤其是初學(xué)者在寫(xiě)代碼的時(shí)候往往都是想一點(diǎn)寫(xiě)一點(diǎn),最開(kāi)始沒(méi)有一個(gè)整體的規(guī)劃,導(dǎo)致后面代碼越寫(xiě)越亂,bug不斷。
最終代碼跑起來(lái)看似沒(méi)有問(wèn)題(有可能也真的沒(méi)有問(wèn)題),但是系統(tǒng)的可擴(kuò)展性很差,添加一個(gè)功能的時(shí)候會(huì)浪費(fèi)大量的時(shí)間,甚至導(dǎo)致整個(gè)代碼的崩潰。
所以,在一個(gè)項(xiàng)目開(kāi)始的時(shí)候多花一些時(shí)間在代碼的架構(gòu)設(shè)計(jì)上是十分有必要的。代碼架構(gòu)確定好了之后你會(huì)發(fā)現(xiàn)敲代碼的時(shí)候會(huì)特別快,并且在后期調(diào)試的時(shí)候也不會(huì)像無(wú)頭蒼蠅一樣胡亂找問(wèn)題。當(dāng)然,調(diào)試也是一門技術(shù)。
在學(xué)習(xí)實(shí)時(shí)操作系統(tǒng)的過(guò)程中,發(fā)現(xiàn)實(shí)時(shí)操作系統(tǒng)框架與個(gè)人的業(yè)務(wù)代碼之間的耦合性就非常低,都是只需要將業(yè)務(wù)代碼通過(guò)一定的接口函數(shù)注冊(cè)好后就交給操作系統(tǒng)托管了,十分方便。
但是操作系統(tǒng)的調(diào)度過(guò)于復(fù)雜,這里就使用操作系統(tǒng)的思維方式來(lái)重構(gòu)這個(gè)時(shí)間片輪詢框架。實(shí)現(xiàn)該框架的完全解耦,用戶只需要包含頭文件,并且在使用過(guò)程中不需要改動(dòng)已經(jīng)寫(xiě)好的庫(kù)文件。
Demo
首先來(lái)個(gè)demo,該demo是使用電腦開(kāi)兩個(gè)線程:一個(gè)線程模擬單片機(jī)的定時(shí)器中斷產(chǎn)生時(shí)間片輪詢個(gè)時(shí)鐘,另一個(gè)線程則模擬主函數(shù)中一直運(yùn)行的時(shí)間片輪詢調(diào)度程序。
#include #include #include #include"timeslice.h" //創(chuàng)建5個(gè)任務(wù)對(duì)象 TimesilceTaskObjtask_1,task_2,task_3,task_4,task_5; //具體的任務(wù)函數(shù) 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"); } //初始化任務(wù)對(duì)象,并且將任務(wù)添加到時(shí)間片輪詢調(diào)度中 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); } //開(kāi)兩個(gè)線程模擬在單片機(jī)上的運(yùn)行過(guò)程 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; }
運(yùn)行結(jié)果如下:

由以上例子可見(jiàn),這個(gè)框架使用十分方便,甚至可以完全不知道其原理,僅僅通過(guò)幾個(gè)簡(jiǎn)單的接口就可以迅速創(chuàng)建任務(wù)并加入到時(shí)間片輪詢的框架中,十分好用。
時(shí)間片輪詢架構(gòu)
其實(shí)該部分主要使用了面向?qū)ο蟮乃季S,使用結(jié)構(gòu)體作為對(duì)象,并使用結(jié)構(gòu)體指針作為參數(shù)傳遞,這樣作可以節(jié)省資源,并且有著極高的運(yùn)行效率。
其中最難的部分是侵入式鏈表的使用,這種鏈表在一些操作系統(tǒng)內(nèi)核中使用十分廣泛,這里是參考RT-Thread實(shí)時(shí)操作系統(tǒng)中的侵入式鏈表實(shí)現(xiàn)。
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內(nèi)核中使用十分廣泛,也十分經(jīng)典,其原理具體可以參考文章:
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;
}
到此,一個(gè)全新的,完全解耦的,十分方便易用時(shí)間片輪詢框架完成。
來(lái)源:小麥大叔
免責(zé)聲明:本文為轉(zhuǎn)載文章,轉(zhuǎn)載此文目的在于傳遞更多信息,版權(quán)歸原作者所有。本文所用視頻、圖片、文字如涉及作品版權(quán)問(wèn)題,請(qǐng)聯(lián)系小編進(jìn)行處理
審核編輯 黃宇
-
單片機(jī)
+關(guān)注
關(guān)注
6078文章
45591瀏覽量
673980 -
框架
+關(guān)注
關(guān)注
0文章
404瀏覽量
18501
發(fā)布評(píng)論請(qǐng)先 登錄
一文說(shuō)透了如何實(shí)現(xiàn)單片機(jī)的多任務(wù)并發(fā)!
一個(gè)面向單片機(jī)、事件驅(qū)動(dòng)的嵌入式開(kāi)發(fā)平臺(tái)介紹
為什么單片機(jī)還在用C語(yǔ)言編程?
單片機(jī)開(kāi)發(fā)中常用的三種軟件架構(gòu)介紹
C語(yǔ)言和單片機(jī)C語(yǔ)言有什么差異
PYQT 應(yīng)用程序框架及開(kāi)發(fā)工具
單片機(jī):一個(gè)承載科技與工程思維的核心平臺(tái)
單片機(jī)燒錄原理是怎樣的?輝芒微單片機(jī)燒錄程序詳細(xì)步驟講解
一種適用于動(dòng)態(tài)環(huán)境的自適應(yīng)先驗(yàn)場(chǎng)景-對(duì)象SLAM框架
非常實(shí)用,推薦一種面向?qū)ο笏季S的單片機(jī)程序框架
評(píng)論