RT-Thread學習記錄11 事件集的使用

以下爲看視頻筆記..........

1. 例說事件集

以坐公交車爲例說明事件集,在公交站等公交車時可能有以下幾種情況:

①P1坐公交車去某地,只有一趟公交車可以到達目的地,等到此公交車即可出發。②P1坐公交車去某地,有3趟公交車都可以到達目的地,等到其中任意一輛即可出發

③P1約另一人P2一起去某地,則P1必須要等到“同伴P2到達公交站”與“公交車到達公交站”兩個條件都滿足後,才能出發。

這裏,可以將P1去某地的這個行爲視爲線程,將“到達目的地的公交車到達公交站”、“同伴P2到達公交站”視爲事件的發生,情況①是特定事件喚醒線程;情況②是任意單個事件喚醒線程;情況③是多個事件同時發生才能喚醒線程。

2. 事件集工作機制

 

信號量主要用於“一對一”的線程同步;當需要“一對多”、“多對一”、“多對多”的同步時,就需要事件集來處理了。

RT-Thread中的事件集用一個32位無符號整型變量來表示,變量中的一個位代表一個事件,線程通過“邏輯與”或“邏輯或”與-一個或多個事件建立關聯形成- -個事件組合。

事件的“邏輯或”也稱爲是獨立型同步,指的是線程與任何事件之一發 生同步,只要有一個事件發生,即滿足條件;

事件的“邏輯與”也稱爲是關聯型同步,指的是線程與若干事件都發生同步,只有這些事件全部發生,才滿足條件。

3. 事件集控制塊

在RT_Thread中,事件集控制塊是操作系統用於管理事件的一個數據結構

struct  rt_event
{
    struct  rt_ipc_object parent;  //從IPC對象繼承過來
    rt_uint32_t           set;     //set是一個32位無符號數,每一位代表一個事件
                                   //若某位是0代表事件沒有發生,1代表發生
}
typedef  struct  rt_ecent  * rt_event_t;

定義靜態事件集;struct  rt_event  static_evt
定義動態事件集:rt_event_t  dynamic_evt

4. 事件集的操作API

初始化與脫離

這組API主要用於靜態事件集的操作,第一個參數是事件集控制塊指針,通過這個API來操作這個事件集event。參數flag可取RT_IPC_FLAG_FIFO,RT_IPC_FLAG_PRIO,表示線程不可用時等待的方式。

rt_err_t  rt_event_init(rt_event_t  event,const char *name,rt_uint8_t  flag)

rt_err_t rt_event_detach(rt_event_t  event)

刪除與創建

這組API主要用於動態事件集的操作

rt_event_t  rt_event_create (const char *name,rt_uint8_t  flag)

rt_err_t rt_event_delete(rt_event_t event)

發送事件

第一個參數表示我們向那一個事件集發送事件,第二個參數是我們發送的事件,若發送是0x08代表是第三個事件發生了

我們可以在線程和中斷服務中使用API去發送事件

rt_err_t rt_event_send(rt_event_t event,rt_uint32_t set)

接受事件

rt_err_t rt_event_recv(rt_event_t event,rt_uint32_t set,rt_uint8_t option,rt_int32_t timeout,rt_uint32_t  *recved)
//第一個參數是事件集線程的指針,即我們要接受那一個事件集的事件,指定事件集
//第二個參數是表示我們對那個事件集哪一個位感興趣,是某些bit的組合,
//第三個參數是事件的信息標記,有RT_EVENT_FLAG_AND(表示set參數的某幾個事件都發生這個函數才能被喚醒),RT_EVENT_FLAG_OR(表示set參數有其中一個事件發生這個函數才能被喚醒),RT_EVENT_FLAG_CLEAR(表示函數喚醒後會清除set參數中的位,即把事件清零).
//函數沒收到事件等待時間,等待會掛起線程,

3. 事件集示例代碼

在event_sample.c中

/*
 * 程序清單:事件例程
 *
 * 程序會初始化2個線程及初始化一個靜態事件對象
 * 一個線程等待於事件對象上,以接收事件;
 * 一個線程發送事件 (事件3/事件5)
*/
#include <rtthread.h>

#define THREAD_PRIORITY      9
#define THREAD_TIMESLICE     5

#define EVENT_FLAG3 (1 << 3)  //第三位是一
#define EVENT_FLAG5 (1 << 5)

/* 事件控制塊 */
static struct rt_event event;

ALIGN(RT_ALIGN_SIZE)
static char thread1_stack[1024];
static struct rt_thread thread1;

/* 線程1入口函數 */
static void thread1_recv_event(void *param)
{
    rt_uint32_t e;

    /* 第一次接收事件,事件3或事件5任意一個可以觸發線程1,接收完後清除事件標誌 */
    if (rt_event_recv(&event, (EVENT_FLAG3 | EVENT_FLAG5),
                      RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
                      RT_WAITING_FOREVER, &e) == RT_EOK)
    {
        rt_kprintf("thread1: OR recv event 0x%x\n", e);
    }

    rt_kprintf("thread1: delay 1s to prepare the second event\n");
    rt_thread_mdelay(1000);

    /* 第二次接收事件,事件3和事件5均發生時纔可以觸發線程1,接收完後清除事件標誌 */
    if (rt_event_recv(&event, (EVENT_FLAG3 | EVENT_FLAG5),
                      RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
                      RT_WAITING_FOREVER, &e) == RT_EOK)
    {
        rt_kprintf("thread1: AND recv event 0x%x\n", e);
    }
    rt_kprintf("thread1 leave.\n");
}


ALIGN(RT_ALIGN_SIZE)
static char thread2_stack[1024];
static struct rt_thread thread2;

/* 線程2入口 */
static void thread2_send_event(void *param)
{
    rt_kprintf("thread2: send event3\n");
    rt_event_send(&event, EVENT_FLAG3);
    rt_thread_mdelay(200);

    rt_kprintf("thread2: send event5\n");
    rt_event_send(&event, EVENT_FLAG5);
    rt_thread_mdelay(200);

    rt_kprintf("thread2: send event3\n");
    rt_event_send(&event, EVENT_FLAG3);
    rt_kprintf("thread2 leave.\n");
}

int event_sample(void)
{
    rt_err_t result;

    /* 初始化事件對象 */
    result = rt_event_init(&event, "event", RT_IPC_FLAG_FIFO);
    if (result != RT_EOK)
    {
        rt_kprintf("init event failed.\n");
        return -1;
    }

    rt_thread_init(&thread1,
                   "thread1",
                   thread1_recv_event,
                   RT_NULL,
                   &thread1_stack[0],
                   sizeof(thread1_stack),
                   THREAD_PRIORITY - 1, THREAD_TIMESLICE);
    rt_thread_startup(&thread1);

    rt_thread_init(&thread2,
                   "thread2",
                   thread2_send_event,
                   RT_NULL,
                   &thread2_stack[0],
                   sizeof(thread2_stack),
                   THREAD_PRIORITY, THREAD_TIMESLICE);
    rt_thread_startup(&thread2);

    return 0;
}

 

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