The use of RT thread learning record 11 event set

Here are the video notes

1. Event set

Taking bus as an example to illustrate the event set, there may be the following situations when waiting for buses at bus stops:

① P1 go to a place by bus, only one bus can arrive at the destination, wait until this bus can start. ② P1 take a bus to a certain place. There are three buses that can reach the destination. Wait for any one of them to start

③ If P1 asks another person P2 to go to a certain place together, P1 must wait until "companion P2 arrives at the bus stop" and "bus arrives at the bus stop" meet both conditions before starting.

Here, the behavior of P1 going to a certain place can be regarded as a thread, and "the bus arriving at the destination arrives at the bus stop" and "the companion P2 arrives at the bus stop" can be regarded as the occurrence of an event. The situation ① is a specific event wake-up thread; the situation ② is any single event wake-up thread; the situation ③ is that multiple events occur at the same time to wake up the thread.







2. Working mechanism of event set

 

Semaphores are mainly used for "one-to-one" thread synchronization. When "one to many", "many to one" and "many to many" synchronization is needed, event sets are needed to handle it.

The event set in RT thread is represented by a 32-bit unsigned integer variable. A bit in the variable represents an event. The thread establishes an association with one or more events through logical and or logical or to form an event combination.

The "logical or" of an event is also called independent synchronization, which means that a thread is synchronized with one of the events. As long as one event occurs, the condition is met;

The "logical and" of an event is also called associated synchronization, which means that a thread synchronizes with several events. Only when all these events occur can the condition be met.





3. Event set control block

At RT_ In thread, the event set control block is a data structure used by the operating system to manage events

struct  rt_event
{
    struct  rt_ipc_object parent;  //Inherited from IPC object
    rt_uint32_t           set;     //set is a 32-bit unsigned number, each bit represents an event
                                   //If a bit is 0, it means the event has not occurred, and 1 means the event has occurred
}
typedef  struct  rt_ecent  * rt_event_t;

//Define static event set_ event  static_ EVT
//Defining dynamic event sets: rt_event_t  dynamic_evt

4. Operation API of event set

Initialization and disengagement

This set of API s is mainly used for static event set operations. The first parameter is the event set control block pointer, which is used to operate this event set event. Parameter flag can be RT_IPC_FLAG_FIFO,RT_IPC_FLAG_PRIO, which indicates how to wait when a thread is unavailable.

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)

Delete and create

This set of API s is mainly used for dynamic event set operations

rt_event_t  rt_event_create (const char *name,rt_uint8_t  flag)

rt_err_t rt_event_delete(rt_event_t event)

Send event

The first parameter indicates which event set we send the event to, and the second parameter is the event we send. If it is 0x08, it means that the third event occurs

We can use API s to send events in threads and interrupt services

rt_err_t rt_event_send(rt_event_t event,rt_uint32_t set)

Accept events

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)
//The first parameter is the pointer of the event set thread, that is, which event set we want to accept and specify the event set
//The second parameter indicates which bit of the event set we are interested in. It is a combination of some bits,
//The third parameter is the information mark of the event, with RT_ EVENT_ FLAG_ And (it means that the function can only be waked up after several events of set parameter occur), RT_ EVENT_ FLAG_ Or (it means that the function can only be waked up when one of the events occurs in the set parameter), RT_ EVENT_ FLAG_ Clear (indicates that the function will clear the bits in the set parameter after waking up, i.e. clear the event)
//The function does not receive the event wait time. Waiting will suspend the thread,

3. Event set example code

At event_ In sample. C

/*
 * Program manifest: event routines
 *
 * The program will initialize 2 threads and a static event object
 * A thread waits on the event object to receive the event;
 * One thread sends events (event 3 / event 5)
*/
#include <rtthread.h>

#define THREAD_PRIORITY      9
#define THREAD_TIMESLICE     5

#define EVENT_ Flag3 (1 < 3) / / the third is one
#define EVENT_FLAG5 (1 << 5)

/* Event control block */
static struct rt_event event;

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

/* Thread 1 entry function */
static void thread1_recv_event(void *param)
{
    rt_uint32_t e;

    /* Any one of event 3 or event 5 can trigger thread 1 for the first time. Clear the event flag after receiving */
    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);

    /* For the second receive event, thread 1 can be triggered only when event 3 and event 5 both occur. Clear the event flag after receiving */
    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;

/* Thread 2 entry */
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;

    /* Initialize event object */
    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;
}

Posted by hewzett on Sun, 14 Jun 2020 20:37:28 -0700