基于C語言構(gòu)建一個獨立棧協(xié)程和共享棧協(xié)程的任務調(diào)度系統(tǒng)
使用了標準庫頭文件 <setjmp.h>
中的 setjmp
和 longjmp
兩個函數(shù),構(gòu)建了一個簡單的查詢式協(xié)作多任務系統(tǒng),支持獨立棧和共享棧兩種任務。
其中涉及到獲取和設置棧的地址操作,因此還需要根據(jù)不同平臺提供獲取和設置棧的地址操作(一般是匯編語言,因為涉及到寄存器)
該調(diào)度系統(tǒng)僅運行在一個實際的線程中,因此本質(zhì)上屬于協(xié)程
獨立棧任務都有自己獨立的運行??臻g,互不干擾;共享棧任務共用一個運行棧空間。
特點
無任務優(yōu)先級搶占的功能。
任務切換的時機完全取決于正在運行的任務,體現(xiàn)協(xié)作。
支持獨立棧和共享棧兩種任務,根據(jù)不同的應用場景決定。
查詢式的調(diào)度方式,當前任務切換時,查詢下個任務是否需要執(zhí)行。
移植性強,只需要修改設置棧和獲取當前棧地址的宏即可。
相對于時間片論法的任務調(diào)度來說,查詢式協(xié)作多任務系統(tǒng)有以下特點:
- 無需使用定時器做為任務調(diào)度
- 每個任務都可以使用
while
循環(huán),用于執(zhí)行任務并保持程序的運行,程序結(jié)構(gòu)清晰 - 每個任務都可以隨時阻塞等待,甚至可以在嵌套的子函數(shù)中阻塞等待
- 通過阻塞等待,無需使用狀態(tài)機等較為復雜的方式來優(yōu)化縮減每個任務的執(zhí)行時長
相對于RTOS操作系統(tǒng)來說,查詢式協(xié)作多任務系統(tǒng)有以下特點:
- 沒有任務優(yōu)先級搶占式的功能,因此臨界資源(中斷除外)和優(yōu)先級反轉(zhuǎn)的問題也不存在
- 允許用戶或應用程序根據(jù)需要自由地切換到下一個就緒任務
- 通過自主調(diào)度和管理任務,查詢式協(xié)作多任務系統(tǒng)可以提高工作效率
- 沒有操作系統(tǒng)的復雜
功能設計
運行??臻g:程序運行中發(fā)生函數(shù)調(diào)用等情況需要使用的棧內(nèi)存空間
獨立棧任務(有棧任務)
每個獨立棧任務都擁有自己獨立的運行棧空間,可以隨時隨地阻塞等待,保存上下文后切換到下一個任務執(zhí)行
獨立棧任務在切換下一個任務時,不會操作運行棧,只對上下文切換
共享棧任務(無棧任務)
每個共享棧任務都沒有自己獨立的運行棧空間,雖然也能阻塞等待,但是僅限于在任務入口函數(shù)中使用,禁止在任務的子函數(shù)(嵌套函數(shù))中阻塞等待;并且在該任務入口函數(shù)中不建議定義相關變量。
- 每個任務有自己的獨立備份棧(用來備份運行棧的棧頂部分數(shù)據(jù));運行棧通常比備份棧要大很多,否則任務函數(shù)無法正常運行多級嵌套的函數(shù)
- 共享棧任務在切換下一個任務時會將當前運行棧(共享棧)提前設置好的備份棧大小(宏配置)拷貝到內(nèi)存?zhèn)浞萜饋?,等下次即將?zhí)行時再從內(nèi)存中拷貝到運行棧(共享棧)進行恢復
- 通過修改加大備份棧大?。ê昱渲茫┑闹?,可以在共享棧任務入口函數(shù)定義變量,這樣可以避免這些變量的值沒有備份導致丟失,或者通過 static 定義局部變量
- 該類型任務適合于輕量的任務處理,一般都是調(diào)用封裝好的函數(shù)即可
注:這里的共享棧任務和常規(guī)的實現(xiàn)有一些差異,常規(guī)的實現(xiàn)是使用堆申請內(nèi)存保存棧的數(shù)據(jù),用多少申請多少進行保存,而這里的實現(xiàn)僅僅保存了一部分數(shù)據(jù)。
任務創(chuàng)建
在調(diào)度系統(tǒng)啟動前,至少要先創(chuàng)建一個任務,否則直接退出
可以在任務中創(chuàng)建新的任務,不管是獨立棧任務還是共享棧任務
- 獨立棧任務中可以創(chuàng)建新的獨立棧任務和共享棧任務
- 共享棧任務中同樣可以創(chuàng)建新的獨立棧任務和共享棧任務,而且在創(chuàng)建共享棧任務時可以使用同一個共享棧
獨立棧任務和共享棧任務一共可以創(chuàng)建最多32個任務(需要修改宏配置)
任務銷毀
- 沒有提供該功能接口函數(shù),任務入口函數(shù)主動退出則自動將任務銷毀。
- 可以通過等待任務退出接口函數(shù)在其他任務中等待該任務退出。
任務阻塞
當前任務阻塞提供兩種方式:
- 時間阻塞:需要阻塞多長時間,等時間滿足后才會繼續(xù)執(zhí)行
- 事件阻塞:通過事件阻塞,只有事件觸發(fā)后才會繼續(xù)執(zhí)行
使用說明
任務創(chuàng)建/退出
對于創(chuàng)建獨立棧任務還是共享棧任務的示例代碼:
uint8_t g_task1Stack[1024 * 2]; uint8_t g_task2Stack[1024 * 2]; uint8_t g_task3Stack[1024 * 2]; uint8_t g_sharedStack[1024 * 2]; // 執(zhí)行完成就退出的任務 void taskfunc3(int arg) { ... cotOs_Wait(1000); ... cotOs_Wait(1000); } void taskfunc1(int arg) { /* 不管taskfunc1是獨立棧任務還是共享棧任務,都支持創(chuàng)建子任務 */ cotOs_CreatTask(taskfunc3, COT_OS_UNIQUE_STACK, g_task3Stack, sizeof(g_task3Stack), 0); // 創(chuàng)建獨立棧任務 cotOs_CreatTask(taskfunc3, COT_OS_SHARED_STACK, g_sharedStack, sizeof(g_sharedStack), 0); // 創(chuàng)建共享棧任務 while (1) { ... cotOs_Wait(1000); } } void taskfunc2(int arg) { while (1) { ... cotOs_Wait(10); } } int main(void) { cotOs_Init(GetTimerMs); #if 0 /* 創(chuàng)建獨立棧任務 */ cotOs_CreatTask(taskfunc1, COT_OS_UNIQUE_STACK, g_task1Stack, sizeof(g_task1Stack), 0); cotOs_CreatTask(taskfunc2, COT_OS_UNIQUE_STACK, g_task2Stack, sizeof(g_task2Stack), 0); #else /* 創(chuàng)建共享棧任務 */ cotOs_CreatTask(taskfunc1, COT_OS_SHARED_STACK, g_sharedStack, sizeof(g_sharedStack), 0); cotOs_CreatTask(taskfunc2, COT_OS_SHARED_STACK, g_sharedStack, sizeof(g_sharedStack), 0); #endif cotOs_Start(); }
任務限制
對于創(chuàng)建獨立棧任務還是共享棧任務,共享棧任務有限制要求,禁止在任務入口函數(shù)的嵌套函數(shù)中阻塞
uint8_t g_task1Stack[1024 * 2]; uint8_t g_sharedStack[1024 * 2]; void func1_1(void) { ... cotOs_Wait(1000); ... cotOs_Wait(1000); } /* 獨立棧任務 */ void taskfunc1(int arg) { int arr[10]; // 可以直接定義變量使用 while (1) { func1_1(); // 可以在嵌套函數(shù)中使用阻塞等待 ... cotOs_Wait(1000); } } void func2_1(void) { ... } /* 共享棧任務 */ void taskfunc2(int arg) { static int arr[10]; // 建議使用static定義任務內(nèi)變量或者不定義變量 while (1) { func2_1(); // 禁止在嵌套函數(shù)中使用阻塞等待 ... cotOs_Wait(10); } } int main(void) { cotOs_Init(GetTimerMs); /* 創(chuàng)建獨立棧任務 */ cotOs_CreatTask(taskfunc1, COT_OS_UNIQUE_STACK, g_task1Stack, sizeof(g_task1Stack), 0); /* 創(chuàng)建共享棧任務 */ cotOs_CreatTask(taskfunc2, COT_OS_SHARED_STACK, g_sharedStack, sizeof(g_sharedStack), 0); cotOs_Start(); }
任務阻塞/退出
通過時間和事件的方式阻塞
uint8_t g_task1Stack[1024 * 2]; uint8_t g_task2Stack[1024 * 2]; uint8_t g_task3Stack[1024 * 2]; uint8_t g_sharedStack[1024 * 2]; CotOSCondition_t g_eventCv; // 執(zhí)行完成就退出的任務 void taskfunc3(int arg) { ... cotOs_ConditionWait(&g_eventCv); ... } void taskfunc1(int arg) { cotOsTask_t task = cotOs_CreatTask(taskfunc3, COT_OS_UNIQUE_STACK, g_task3Stack, sizeof(g_task3Stack), 0); while (1) { ... cotOs_Wait(1000); if (...) { // 等待 taskfunc3 任務運行結(jié)束后才退出 taskfunc1 cotOs_Join(task); break; } } } void taskfunc2(int arg) { while (1) { ... cotOs_Wait(10); if (...) { cotOs_ConditionNotify(&g_eventCv); // 通知 taskfunc3 繼續(xù)執(zhí)行 } } } int main(void) { cotOs_Init(GetTimerMs); cotOs_CreatTask(taskfunc1, COT_OS_SHARED_STACK, g_sharedStack, sizeof(g_sharedStack), 0); cotOs_CreatTask(taskfunc2, COT_OS_SHARED_STACK, g_sharedStack, sizeof(g_sharedStack), 0); cotOs_Start(); }
不同棧類型任務應用場景
獨立棧任務(有棧任務)
- 重量級任務: 提供更多的控制,適用于需要更精確地管理任務狀態(tài)的情況和執(zhí)行計算密集型任務的場景
- 更可預測的內(nèi)存使用: 在創(chuàng)建時分配??臻g,可以更好地控制內(nèi)存使用,適用于需要更可預測內(nèi)存行為的場景
- 遞歸調(diào)用: 更容易處理遞歸調(diào)用,因為每個任務都有獨立的??臻g
共享棧任務(無棧任務)
- 輕量級任務: 通常更輕量,適用于大量小任務的場景。
- 內(nèi)存效率: 適用于內(nèi)存受限的環(huán)境,因為不需要為每個任務分配各自的??臻g(備份棧除外)。
代碼鏈接
以上就是基于C語言構(gòu)建一個獨立棧協(xié)程和共享棧協(xié)程的任務調(diào)度系統(tǒng)的詳細內(nèi)容,更多關于C語言任務調(diào)度系統(tǒng)的資料請關注腳本之家其它相關文章!
相關文章
vscode調(diào)試gstreamer源碼的詳細流程
在本文中主要介紹了如何使用vscode調(diào)試C++和python程序,并進一步分析了如何調(diào)試gstreamer源碼,講述了如何調(diào)試gstreamer源碼的具體流程,感興趣的朋友跟隨小編一起看看吧2023-01-01