contiki學習筆記03

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這個位置了,這個琢磨一下就能想通的。

流程圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章