利用C語(yǔ)言實(shí)現(xiàn)任務(wù)調(diào)度的示例代碼
前言
這個(gè)任務(wù)調(diào)度模塊的實(shí)現(xiàn)是形成于畢設(shè)項(xiàng)目中的,用在STM32
中,斷斷續(xù)續(xù)跨度2個(gè)月實(shí)現(xiàn)了一些基本功能,可能后面再做其他項(xiàng)目時(shí)會(huì)一點(diǎn)點(diǎn)完善起來(lái),也會(huì)多學(xué)習(xí)相關(guān)知識(shí)來(lái)強(qiáng)化模塊的實(shí)用性和高效性,畢竟用自己自主實(shí)現(xiàn)出來(lái)的功能還是蠻舒心的。
任務(wù)調(diào)度模式結(jié)構(gòu)
整體上的結(jié)構(gòu)屬于線性結(jié)構(gòu),結(jié)合鏈表和定時(shí)器來(lái)實(shí)現(xiàn),我使用的是sysTick
這個(gè)滴答時(shí)鐘,1ms
的頻率,功能比較簡(jiǎn)單,容易理解。
分片
分片的模式,主要體現(xiàn)在函數(shù)分片和時(shí)間分片在我之前就有使用在函數(shù)中,主要的思路是,把函數(shù)功能切片,分為幾個(gè)小部分,每次執(zhí)行時(shí)按次序執(zhí)行小部分,對(duì)于沒(méi)有時(shí)序要求的函數(shù)來(lái)說(shuō),可以把一個(gè)占用CPU
大的功能分?jǐn)傞_來(lái)實(shí)現(xiàn),從而避免有些地方耗時(shí)長(zhǎng)的問(wèn)題。對(duì)于時(shí)間分片,其實(shí)就是定時(shí)器的一種應(yīng)用,實(shí)際上,函數(shù)分片在執(zhí)行的時(shí)候已經(jīng)是一種時(shí)間分片了,不過(guò)現(xiàn)在加上人為的控制在里面了。
下面是函數(shù)分片的一般結(jié)構(gòu):
void func(char *fos,...){ static char step=0;//順序控制變量,自由度比較高,可亂序,可循環(huán),可延遲執(zhí)行 switch(step){ case 0:{ //... step++; break; } case 1:{ //... step++; break; } //... default:{ //step++;//可以借助default實(shí)現(xiàn)延時(shí)的效果,即跳過(guò)幾次空白step break; } } return; }
其中添加的參數(shù)變量*fos
是必要的,因?yàn)榫褪峭ㄟ^(guò)傳入每個(gè)任務(wù)的這個(gè)標(biāo)志位來(lái)判斷是否運(yùn)行結(jié)束,而其他的參數(shù),就得基于具體任務(wù)做不一樣的處理了。
輪詢
運(yùn)行框圖
可以看到這個(gè)框圖是一個(gè)頭尾相連的閉環(huán)結(jié)構(gòu),從頭節(jié)點(diǎn)依次運(yùn)行到尾節(jié)點(diǎn)后再?gòu)念^循環(huán)往復(fù)執(zhí)行下去。
輪詢函數(shù)
void loop_task(void){ static Task_Obj *tasknode; tasknode=task_curnode->next;//repoint the curnode to the next if(tasknode==NULL){//tasknode is null,only the headnode have the attr return;//express the task space is none } else if(tasknode->task_type==TYPE_HEAD){//tasknode is headnode task_curnode=tasknode; return; } else{ if(tasknode->run_type == RUN_WAIT){ //等待型任務(wù),通過(guò)ready標(biāo)志來(lái)確定是否執(zhí)行,否則就跳過(guò) if(!tasknode->ready){ if(task_curnode->next !=NULL){ task_curnode=task_curnode->next; return; } } } if(tasknode->task_status==STATUS_INIT){ tasknode->tickstart=HAL_GetTick();//獲取tick tasknode->task_status=STATUS_RUN; } else if(tasknode->task_status==STATUS_RUN){ if((HAL_GetTick() - tasknode->tickstart) > (uint32_t)tasknode->task_tick){ tasknode->task_name(&(tasknode->task_fos));//run the step task,transfer the fos tasknode->tickstart+=(uint32_t)tasknode->task_tick;//update the tickstart } } } if(tasknode->task_fos==FOS_FLAG){ tasknode->ready=0; if(tasknode->waittask!=NULL){ //置位該任務(wù)綁定的等待的任務(wù)準(zhǔn)備運(yùn)行標(biāo)志位,標(biāo)識(shí)可以準(zhǔn)備運(yùn)行了 tasknode->waittask->ready=1; } //運(yùn)行結(jié)束就刪掉該任務(wù) delete_task(tasknode); } else if(tasknode->task_fos==FOC_FLAG){ //循環(huán)運(yùn)行該任務(wù) tasknode->task_status=STATUS_INIT;//continue running from start tasknode->task_fos=0;//RESET fos } if(task_curnode->next !=NULL){ if(task_curnode->next->run_type==RUN_FORCE) return;//force-type's task else task_curnode=task_curnode->next; } }
其中有幾個(gè)運(yùn)行態(tài)和標(biāo)志位
#define FOS_FLAG 99//運(yùn)行結(jié)束標(biāo)志 #define FOC_FLAG 100//運(yùn)行結(jié)束后再次執(zhí)行,相當(dāng)于循環(huán)運(yùn)行 #define TYPE_NOMAL 0//標(biāo)識(shí)一般任務(wù)類型 #define TYPE_HEAD 1//標(biāo)識(shí)頭任務(wù)類型 #define TYPE_END 2//標(biāo)識(shí)尾任務(wù)類型 #define RUN_NORMAL 0//一般輪詢模式 #define RUN_FORCE 1//強(qiáng)制運(yùn)行該任務(wù),運(yùn)行結(jié)束才繼續(xù)下一個(gè)任務(wù) #define RUN_WAIT 2//等待指定的任務(wù)結(jié)束,才可以被運(yùn)行 #define STATUS_INIT 0//任務(wù)的準(zhǔn)備階段,用于獲取起始時(shí)間 #define STATUS_RUN 1//任務(wù)運(yùn)行階段 #define STATUS_UNVAILED 2//無(wú)效狀態(tài)
運(yùn)行時(shí)對(duì)時(shí)間間隔tick
的把握還有點(diǎn)問(wèn)題,這個(gè)等待后面有機(jī)會(huì)優(yōu)化下。
調(diào)度實(shí)現(xiàn)
任務(wù)鏈表結(jié)構(gòu)
typedef struct TASK_CLASS{ void (*task_name)(char *taskfos,...);//任務(wù)函數(shù) int task_tick;//任務(wù)的時(shí)間分片間隔 uint32_t tickstart;//起始時(shí)間點(diǎn),每次執(zhí)行完須加上一個(gè)tick char task_fos;//運(yùn)行結(jié)束標(biāo)志 char task_type;//任務(wù)類型變量 char task_status;//任務(wù)狀態(tài) char run_type;//運(yùn)行狀態(tài) char ready;//準(zhǔn)備運(yùn)行標(biāo)志位 struct TASK_CLASS *next;//下一任務(wù) struct TASK_CLASS *waittask;//等待執(zhí)行的任務(wù) } Task_Obj;
添加任務(wù)
add_task
void add_task(void (*taskname)(char *,...),int tasktick,int runtype){//可變參,這里未做處理 Task_Obj *tasknode,*tmpnode; char i; tasknode = (Task_Obj*)malloc(sizeof(Task_Obj)); tasknode->task_name=taskname; tasknode->task_tick=tasktick; tasknode->task_fos=0; tasknode->task_status=STATUS_INIT;//initial status tasknode->task_type=TYPE_END; //set the new node to endnode tasknode->run_type=runtype; tasknode->next=&task_headnode;//the endnode point to the headnode tmpnode=&task_headnode; if(task_num==0){ tmpnode->next=tasknode; task_num++; return; } for(i=0;i<task_num;i++){ tmpnode=tmpnode->next;//reach the endnode } tmpnode->task_type=TYPE_NOMAL;//turn the last endnode to the normal node tmpnode->next=tasknode; task_num++; }
add_wait_task
void add_wait_task(void (*taskname)(char *),void (*waitname)(char *),int tasktick){ Task_Obj *tmpnode,*tasknode; char i,pos; tmpnode=&task_headnode; for(i=0;i<task_num;i++){ tmpnode=tmpnode->next;//reach the endnode if(tmpnode->task_name==taskname){ pos=i;//獲取要等待任務(wù)的位置 break; } } tasknode = (Task_Obj*)malloc(sizeof(Task_Obj)); tasknode->task_name=waitname; tasknode->task_tick=tasktick; tasknode->task_fos=0; tasknode->task_status=STATUS_INIT;//initial status tasknode->task_type=TYPE_END; //set the new node to endnode tasknode->run_type=RUN_WAIT;//任務(wù)為等待運(yùn)行 tasknode->ready=0; tasknode->next=&task_headnode;//the endnode point to the headnode tmpnode->waittask=tasknode;//獲取新建的等待執(zhí)行的任務(wù)地址,在運(yùn)行結(jié)束后把等待執(zhí)行的任務(wù)的準(zhǔn)備運(yùn)行標(biāo)志位置1 tmpnode=&task_headnode; if(task_num==0){ tmpnode->next=tasknode; task_num++; return; } for(i=0;i<task_num;i++){ tmpnode=tmpnode->next;//reach the endnode } tmpnode->task_type=TYPE_NOMAL;//turn the last endnode to the normal node tmpnode->next=tasknode; task_num++; }
刪除任務(wù)
delete_task(局限性大,只針對(duì)當(dāng)前運(yùn)行的任務(wù)而言)
void delete_task(Task_Obj *taskobj){ if(task_curnode->task_type==TYPE_HEAD && task_num < 2){//if curnode is headnode,and tasknum=1 task_curnode->next=NULL; } else{ task_curnode->next=taskobj->next;//repoint the curnode next } free(taskobj);//free the space of where the taskobj pointed task_num--; }
delete_task_withname(刪除指定任務(wù)名的任務(wù))
void delete_task_withname(void (*taskname)(char *)){ Task_Obj *tmpnode,*tmpnode2; char i,pos; tmpnode=&task_headnode; for(i=0;i<task_num;i++){ tmpnode=tmpnode->next;//reach the endnode if(tmpnode->task_name==taskname){ pos=i; break; } } if(i==task_num) return; tmpnode=&task_headnode; for(i=0;i<pos+1;i++){ tmpnode2=tmpnode; tmpnode=tmpnode->next; } if(tmpnode->next==NULL){//if tmpnode is endnode tmpnode2->next=&task_headnode; } else{ tmpnode2->next=tmpnode->next;//repoint the curnode next } task_num--; free(tmpnode); }
初始化任務(wù)空間
void non_task(char *taskfos){ return; } void init_taskspace(void){ task_headnode.task_name=non_task; task_headnode.task_type=TYPE_HEAD; task_headnode.task_status=STATUS_UNVAILED; task_headnode.next=NULL; task_curnode=&task_headnode;//頭節(jié)點(diǎn)是沒(méi)有任務(wù)需要執(zhí)行的 task_num=0; }
調(diào)用實(shí)例
add_task(task1,500,RUN_NORMAL);//500ms執(zhí)行一次task1任務(wù) add_wait_task(task1,task2,500);//task2等待task1結(jié)束才會(huì)執(zhí)行,運(yùn)行的時(shí)間間隔為500ms delete_task_withname(task1);//刪除task1任務(wù) while(1){ //... loop_task();//任務(wù)輪詢 }
結(jié)語(yǔ)
整體實(shí)現(xiàn)說(shuō)難不難,說(shuō)簡(jiǎn)單不簡(jiǎn)單,但也是我第一次嘗試這種偏向系統(tǒng)級(jí)應(yīng)用的代碼,而且都沒(méi)有參照任何其他的資料和代碼,完全以自己的對(duì)任務(wù)的理解和具體項(xiàng)目的需求來(lái)一點(diǎn)點(diǎn)實(shí)現(xiàn),希望后面會(huì)把這個(gè)調(diào)度的代碼進(jìn)一步完善成一個(gè)通用型的調(diào)度方式,也方便后面項(xiàng)目的使用了。
到此這篇關(guān)于利用C語(yǔ)言實(shí)現(xiàn)任務(wù)調(diào)度的示例代碼的文章就介紹到這了,更多相關(guān)C語(yǔ)言任務(wù)調(diào)度內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言非遞歸算法解決快速排序與歸并排序產(chǎn)生的棧溢出
上期我們講完了排序算法下,不知道小伙伴們有沒(méi)有發(fā)現(xiàn)一個(gè)問(wèn)題,快速排序和歸并排序我們都是用遞歸來(lái)實(shí)現(xiàn)的,可能有小伙伴會(huì)問(wèn),如果說(shuō)數(shù)據(jù)量很多話,棧區(qū)空間會(huì)不會(huì)不夠用呢?這期我們就來(lái)解決使用遞歸實(shí)現(xiàn)的排序?qū)е聴R绯鋈绾谓鉀Q2022-04-04C++中Semaphore內(nèi)核對(duì)象用法實(shí)例
這篇文章主要介紹了C++中Semaphore內(nèi)核對(duì)象用法實(shí)例,有助于深入了解信號(hào)量(Semaphore)的基本用法,需要的朋友可以參考下2014-10-10Qt實(shí)現(xiàn)繪制網(wǎng)格背景的示例代碼
這篇文章主要介紹了Qt如何實(shí)現(xiàn)繪制網(wǎng)格背景,并且能實(shí)現(xiàn)窗口大小調(diào)整時(shí)網(wǎng)格背景也自動(dòng)調(diào)整重繪,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-06-06C/C++編程語(yǔ)言中的指針(pointer)你了解嗎
這篇文章主要為大家詳細(xì)介紹了C/C++編程語(yǔ)言中的指針,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-02-02C和C++如何實(shí)現(xiàn)互相調(diào)用詳解
在學(xué)習(xí)c++中用到一些古老的c語(yǔ)言庫(kù)時(shí),在工作中我們經(jīng)常要使用C和C++混合編程,下面這篇文章主要給大家介紹了關(guān)于C和C++如何實(shí)現(xiàn)互相調(diào)用的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01C++ map與set封裝實(shí)現(xiàn)過(guò)程講解
set set是一種關(guān)聯(lián)式容器,下面這篇文章主要給大家介紹了關(guān)于C++中map和set使用的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-03-03