修改了下参考文档中的事件集例程,采用RT_IPC_FLAG_FIFO方式,线程1和3等待相同事件集(事件接受设置为不清除),事件集唤醒线程后则打印线程退出;线程2发送事件集。结果显示线程1、3唤醒的顺序与线程挂起的顺序无关,与线程1、3优先级有关,高优先级先执行,低优先级后执行。
注:
1)RTT:V4.0.3, IDE:VSCode , BSP:qemu-express-a9
线程1初始化后延时100ms等待事件集;线程3初始化后直接等待事件集;即等待顺序为线程3在前,线程1在后,Finsh执行list_event看到的等待线程顺序与此一致;
2)测试代码优先级线程1高于线程3,等待顺序为线程3、线程1,线程接收事件集顺序为线程1、线程3,即与先进先出不符,与优先级相符;
3)交换线程1、线程3优先级,则线程接收事件集顺序为线程3、线程1,还是与优先级相符。
请问是不是对FIFO方式理解有误,线程等待顺序与等待线程列表里的顺序不是一回事?理解是否可推广道其它同步方式?
测试代码:
#include <rtthread.h>
#include "thread_exp.h"
#define THREAD_PRIORITY 9
#define THREAD_TIMESLICE 5
#define EVENT_FLAG1 (1 << 0)
#define EVENT_FLAG2 (1 << 1)
#define EVENT_FLAG3 (1 << 2)
#define EVENT_FLAG4 (1 << 3)
#define EVENT_FLAG5 (1 << 4)
#define EVENT_FLAG6 (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;
/*
rt_kprintf("thread1 waitting for 1 and 2.\n");
if (rt_event_recv(&event, (EVENT_FLAG1 | EVENT_FLAG2),
RT_EVENT_FLAG_AND | 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(100);
rt_kprintf("thread1 waitting for 4 and 5.\n");
if (rt_event_recv(&event, (EVENT_FLAG4 | EVENT_FLAG5),
RT_EVENT_FLAG_AND,
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 thread3_stack[1024];
static struct rt_thread thread3;
/* 线程 1 入口函数 */
static void thread3_recv_event(void *param)
{
rt_uint32_t e;
rt_kprintf("thread3 waitting for 4 and 5.\n");
/* 第二次接收事件,事件 3 和事件 5 均发生时才可以触发线程 1,接收完后清除事件标志 */
if (rt_event_recv(&event, (EVENT_FLAG4 | EVENT_FLAG5),
RT_EVENT_FLAG_AND,
RT_WAITING_FOREVER, &e) == RT_EOK)
{
rt_kprintf("thread3: AND recv event 0x%x\n", e);
}
rt_kprintf("thread3 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_thread_mdelay(2000);
rt_kprintf("thread2: send event1\n");
rt_event_send(&event, EVENT_FLAG1);
rt_thread_mdelay(200);
rt_kprintf("thread2: send event2\n");
rt_event_send(&event, EVENT_FLAG2);
rt_thread_mdelay(200);
rt_kprintf("thread2: send event3\n");
rt_event_send(&event, EVENT_FLAG3);
rt_thread_mdelay(200);
rt_kprintf("thread2: send event4\n");
rt_event_send(&event, EVENT_FLAG4);
rt_thread_mdelay(200);
rt_kprintf("thread2: send event5\n");
rt_event_send(&event, EVENT_FLAG5);
rt_kprintf("thread2 leave.\n");
}
int event_sample(void)
{
rt_err_t result;
//rt_scheduler_sethook(hook_of_scheduler);
/* 初始化事件对象 */
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 - 2, THREAD_TIMESLICE);
rt_thread_startup(&thread1);
rt_thread_init(&thread3,
"thread3",
thread3_recv_event,
RT_NULL,
&thread3_stack[0],
sizeof(thread3_stack),
THREAD_PRIORITY-1, THREAD_TIMESLICE);
rt_thread_startup(&thread3);
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;
}
结果如下:
\ | /
- RT - Thread Operating System
/ | \ 4.0.3 build Aug 16 2021
2006 - 2021 Copyright by rt-thread team
lwIP-2.0.2 initialized!
[32m[I/sal.skt] Socket Abstraction Layer initialize success.[0m
[32m[I/SDIO] SD card capacity 65536 KB.[0m
[32m[I/SDIO] switching card to high speed failed![0m
hello rt-thread
msh />ev
event_sample
msh />event_sample
thread3 waitting for 4 and 5.
msh />thread1 waitting for 4 and 5.
thread2: send event1
thread2: send event2
thread2: send event3
thread2: send event4
thread2: send event5
thread1: AND recv event 0x18
thread1 leave.
thread3: AND recv event 0x18
thread3 leave.
thread2 leave.
我也是这样理解的 但前述的试验结果跟这个不一致
@coolouba 对,看到了,说明你发现了这个bug,官方在 github 上有过这个提醒,最新版也把很多使用 RT_IPC_FLAG_FIFO 的地方修改了。
好的 谢谢