首先颁虐,協(xié)程的英文名是coroutine芒澜,是一種非搶占的任務(wù)形式仰剿。協(xié)程有很多種實(shí)現(xiàn)方式,Contiki里引入的PT協(xié)程痴晦,C語(yǔ)言標(biāo)準(zhǔn)庫(kù)里的setjmp.h等等南吮,都可以實(shí)現(xiàn)協(xié)程。協(xié)程運(yùn)行的時(shí)候誊酌,是以禪讓的方式退出的部凑,也就是說(shuō)我運(yùn)行夠了才會(huì)退出讓別人運(yùn)行。PT協(xié)程的幾種實(shí)現(xiàn)方式這里就不一一說(shuō)明了术辐,在網(wǎng)上可以找到不少資料砚尽。這里只是說(shuō)一下VSF中的事件驅(qū)動(dòng)的PT協(xié)程。
vsf_err_t example_thread(struct vsfsm_pt_t *pt, vsfsm_evt_t evt)
{
vsfsm_pt_begin(pt);
while (1)
{
......
vsfsm_pt_entry(pt);
......
vsfsm_pt_entry(pt);
......
}
vsfsm_pt_end(pt);
}
VSF中的PT協(xié)程核心只是vsfsm_pt_begin辉词、vsfsm_pt_end和vsfsm_pt_entry敷搪。vsfsm_pt_begin在程序入口幢哨,功能為根據(jù)PT的狀態(tài),跳轉(zhuǎn)到對(duì)應(yīng)的entry繼續(xù)執(zhí)行闸与,如果狀態(tài)為0厂画,就不跳轉(zhuǎn)繼續(xù)往下執(zhí)行。vsfsm_pt_end是邏輯結(jié)構(gòu)上用的忽洛,表示PT協(xié)程代碼結(jié)束。vsfsm_pt_entry就是把當(dāng)前的執(zhí)行位置苍在,記錄到PT的狀態(tài)里,使得下一次調(diào)用的時(shí)候初肉,可以從記錄的位置開(kāi)始執(zhí)行。
上面的PT原理妄壶,其實(shí)都是通用的,不過(guò)VSF中的PT是設(shè)計(jì)為事件驅(qū)動(dòng)的PT,也就是說(shuō)屑埋,PT實(shí)際上续崖,底層也只是一個(gè)evt_handler(事件處理函數(shù))。
static struct vsfsm_state_t *
vsfsm_pt_evt_handler(struct vsfsm_t *sm, vsfsm_evt_t evt)
{
struct vsfsm_pt_t *pt = (struct vsfsm_pt_t *)sm->user_data;
switch (evt)
{
case VSFSM_EVT_ENTER:
case VSFSM_EVT_EXIT:
break;
case VSFSM_EVT_INIT:
pt->state = 0;
// fall through
default:
pt->thread(pt, evt);
}
return NULL;
}
上面是VSF中的通用的PT底層的事件驅(qū)動(dòng)接口梢莽,只是在初始化事件中,初始化了PT的狀態(tài)變量轻局,然后除了ENTER和EXIT事件外置鼻,其他事件都直接調(diào)用PT線程來(lái)處理。從PT的初始化代碼中钙勃,也可以看出VSF中的PT是基于事件驅(qū)動(dòng)狀態(tài)機(jī)的:
vsf_err_t vsfsm_pt_init(struct vsfsm_t *sm, struct vsfsm_pt_t *pt)
{
sm->user_data = pt;
sm->init_state.evt_handler = vsfsm_pt_evt_handler;
pt->sm = sm;
return vsfsm_init(sm);
}
實(shí)際應(yīng)用代碼中同木,一般不會(huì)直接調(diào)用vsfsm_pt_entry,而且調(diào)用其他的輔助宏或者函數(shù):vsfsm_pt_wait远豺、vsfsm_pt_wfe(wait for event)、vsfsm_pt_wfpt(wait for pt)丽涩。分別代表等待下一個(gè)事件棺滞、等待直到收到指定事件、等待一個(gè)PT任務(wù)調(diào)用完成。這里只列舉一個(gè)vsfsm_pt_wfe的定義:
#define vsfsm_pt_wfe(pt, e) \
do {\
evt = VSFSM_EVT_INVALID;\
vsfsm_pt_entry(pt);\
if (evt != (e)) return VSFERR_NOT_READY;\
} while (0)
VSF中的PT協(xié)程返回VSFERR_NOT_READY表示還沒(méi)執(zhí)行完矮男;返回VSFERR_NONE表示已經(jīng)執(zhí)行完崔泵;如果返回小于0的指,則表示執(zhí)行出錯(cuò)。
按照PT協(xié)程的特性塞弊,一般適合用于“阻塞”代碼漱逸,實(shí)現(xiàn)后,運(yùn)行的方式確是非阻塞的游沿。當(dāng)然袋坑,也會(huì)有一些注意點(diǎn),比如
- 如果PT使用switch的方式事件的話眯勾,PT協(xié)程中的switch塊不能包含vsfsm_pt_entry枣宫。
- 由于PT協(xié)程是非阻塞婆誓,并不是一次調(diào)用就執(zhí)行完畢的,會(huì)分成多次調(diào)用也颤,所以洋幻,PT協(xié)程里的非靜態(tài)變量在一下次調(diào)用的時(shí)候,數(shù)值不同翅娶。