contiki學習筆記03
contiki是基於事件型驅動的操作系統,它傳遞事件的方式有兩種,同步和異步。 process_post_synch
函數是同步,調用它可以馬上執行相關的線程;process_post
是異步,調用它會產生一個事件,等待下次在主函數中執行;具體看代碼:
void process_post_synch(struct process *p, process_event_t ev,
process_data_t data)
{
/* 定義一個指針變量,用來存儲當前線程的指針 */
struct process *caller = process_current;
/* 調用執行線程 */
call_process(p, ev, data);
/* 再賦值回來 */
process_current = caller;
}
這邊第一次看的時候有個地方不懂,爲什麼要保存當前的線程指針,看了call_process
這個函數的實現方式後才懂,這個下面再說;同步傳遞事件的實現比較簡單,就到此結束了。
現在來看下異步同步方式,contiki建了個數組,用來存儲待處理的事件,nevents
是還未處理的事件總數,fevent
是下次將要處理的事件下標;
static process_num_events_t nevents, fevent;
static struct event_data events[PROCESS_CONF_NUMEVENTS];
其中event_data
是自定義的事件類型,裏面主要有3個成員,1是事件類型,2是數據指針,3是線程指針
struct event_data
{
process_event_t ev; /* typedef unsigned char process_event_t; */
process_data_t data; /* typedef void *process_data_t; */
struct process *p;
};
下面的代碼就是異步的同步方式,雖然看起來有很多,但真正發揮作用的只有不到10行代碼,它第一步先判斷是後已經滿了(在20行),如果已經滿了則退出;否則就添加到數組裏面去
int process_post(struct process *p, process_event_t ev, process_data_t data)
{
/* 臨時變量,用來標識當前要傳遞的事件放在哪裏 */
process_num_events_t snum;
/* 當前沒有其他線程在運行,換句話說當前傳遞者不是線程 */
if (PROCESS_CURRENT() == NULL)
{
PRINTF("process_post: NULL process posts event %d to process '%s', nevents %d\r\n",
ev, PROCESS_NAME_STRING(p), nevents);
}
else
{
PRINTF("process_post: Process '%s' posts event %02X to process '%s', nevents %d\r\n",
PROCESS_NAME_STRING(PROCESS_CURRENT()), ev,
p == PROCESS_BROADCAST ? "<broadcast>" : PROCESS_NAME_STRING(p), nevents);
}
/* 還未處理的線程總數已經滿了(放不進來),退出 */
if (nevents == PROCESS_CONF_NUMEVENTS)
{
#if DEBUG
if (p == PROCESS_BROADCAST)
{
printf("soft panic: event queue is full when broadcast event %02X was posted from %s\r\n",
ev, PROCESS_NAME_STRING(process_current));
}
else
{
printf("soft panic: event queue is full when event %02X was posted to %s from %s\r\n",
ev, PROCESS_NAME_STRING(p), PROCESS_NAME_STRING(process_current));
}
#endif /* DEBUG */
return PROCESS_ERR_FULL;
}
/* 計算下標,fevent是將要處理的事件下標,nevets是總爲處理下標
PROCESS_CONF_NUMEVENTS 是總的能存放爲處理的事件總數 */
snum = (process_num_events_t)(fevent + nevents) % PROCESS_CONF_NUMEVENTS;
events[snum].ev = ev;
events[snum].data = data;
events[snum].p = p;
/* 總數+1 */
++nevents;
return PROCESS_ERR_OK;
}
這裏面基本都好理解,比較難理解的是第41行了,snum = (process_num_events_t)(fevent + nevents) % PROCESS_CONF_NUMEVENTS;
爲什麼下標可以這樣計算:舉個例子,PROCESS_CONF_NUMEVENTS
最大是10,nevents
目前是5,代表有5個未處理的事件,fevent
目前已經處理到了第3個事件,即fevent
目前等於3,這時候要把新的事件存在哪裏呢?只能存在8這個位置,因爲目前要處理的下標是3,還有5個事件待處理,所以只能存在8這個位置了,這個琢磨一下就能想通的。