[FreeRTOS 内部实现] 事件组


事件组结构体

// 路径:Source/event_groups.c
typedef struct xEventGroupDefinition
{
	EventBits_t uxEventBits;
	List_t xTasksWaitingForBits;		
} EventGroup_t;

uxEventBits 中的每一位表示某个事件是否发生。 具体事件由程序员来确定,大小为uint32_t。
xTasksWaitingForBits 为等待事件链表。 若某个事件检测到uxEventBits中所需要的位没有置位,就会将自己保存在该链表中等待。


创建事件组

使用 xEventGroupCreate 函数进行事件组创建

EventGroupHandle_t xEventGroupCreate( void )
	// 1、申请事件组结构体 EventGroup_t 空间
	-> pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) );
	// 2、初始化结构体中uxEventBits 事件位
	-> pxEventBits->uxEventBits = 0;
	// 3、初始化等待事件组链表
	vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );

事件组等待位

使用xEventGroupWaitBits 函数进行事件等待,函数定义如下:

EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )

第一参数 EventGroupHandle_t xEventGroup :已经申请并且需要操作事件组句柄
第二参数 const EventBits_t uxBitsToWaitFor :等待的位有哪些
第三参数 const BaseType_t xClearOnExit :在退出的时候是否对等待的位进行清除
第四参数 const BaseType_t xWaitForAllBits:等待的位是同时满足还是只要一个成立就满足(等待位是 与的关系 还是 或的关系 )
第五参数 TickType_t xTicksToWait :等待的时间

EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
	// 1、关闭调度器,后面有详解
	-> vTaskSuspendAll();	
	{
		// 2、检查等待条件是否已经满足
		const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;
		xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );
		// 3、等待条件已经满足,所以没有必要阻塞
		if( xWaitConditionMet != pdFALSE )	
		{
			// 4、判断退出前xClearOnExit 是否清零
			if( xClearOnExit != pdFALSE )
				pxEventBits->uxEventBits &= ~uxBitsToWaitFor;		// 清零
		}
		// 判断是否愿意等待
		else if( xTicksToWait == ( TickType_t ) 0 )
			uxReturn = uxCurrentEventBits;		// 不愿意等待,退出
		else
		{
			// 记录标志位
			if( xClearOnExit != pdFALSE )
				uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;
			if( xWaitForAllBits != pdFALSE )
				uxControlBits |= eventWAIT_FOR_ALL_BITS;
		}
		// 将调用任务正在等待的比特存储在任务的事件中列表项,以便内核知道何时找到匹配项。然后进入阻塞状态
		vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );
			// 把当前任务加入xEventListItem 链表中
			-> 	listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE );	
			-> 	vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) );
			// 把当前任务从就绪链表移到等待链表中
			-> 	prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
	}

vTaskSuspendAll函数 功能是关闭调度器。在之前的队列操作(包含信号量和互斥量操作)中无论是读还是写操作,第一步就是关中断。而在操作事件组的时候第一步却不需要直接关闭中断,只需要关闭调度器,这两者有什么区别呢?

对于队列操作,存在两种情况:
1、多个任务同时操作队列
2、中断 过程中可以对队列进行读写操作
考虑到第一种情况,多任务之间操作队列会相互影响,可以采取关闭调度器来解决,但是不能屏蔽掉中断中对队列的读写操作。如果只关闭调度器的话,中断对队列的操作同样会对正在的任务有影响。因此任务在对队列进行操作时,第一步一定是要关闭中断。

对于事件组操作,只存在任务之间的操作,中断过程中不会对事件组进行操作,因此只需要关闭调度器就可以实现任务之间对事件组操作的互斥。

在这里插入图片描述


事件组设置位

使用xEventGroupSetBits 函数进行事件设置

EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
	-> vTaskSuspendAll();	// 关闭调度器
	{
		// 1、设置对应的位
		pxEventBits->uxEventBits |= uxBitsToSet;
		// 2、唤醒所有满足条件的任务
		while( pxListItem != pxListEnd )
		{
			if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 )
			{
				if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 )
					xMatchFound = pdTRUE;
				else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor )
					xMatchFound = pdTRUE;
				// 从链表中移除
				vTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );
		}
	}

相关推荐

  1. 11.FreeRTOS_事件

    2024-07-10 11:12:05       24 阅读
  2. FreeRTOS学习笔记-基于stm32(10)事件标志

    2024-07-10 11:12:05       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 11:12:05       99 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 11:12:05       107 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 11:12:05       90 阅读
  4. Python语言-面向对象

    2024-07-10 11:12:05       98 阅读

热门阅读

  1. PHP的发展历程以及功能使用场景

    2024-07-10 11:12:05       31 阅读
  2. Redis哨兵模式与集群模式的快速部署

    2024-07-10 11:12:05       25 阅读
  3. 单片机与FPGA的关系及其在嵌入式系统中的应用

    2024-07-10 11:12:05       32 阅读
  4. Hadoop中的副本、校验和(数字指纹)、block

    2024-07-10 11:12:05       21 阅读
  5. Xshell 和宝塔有啥区别

    2024-07-10 11:12:05       29 阅读
  6. SD卡,laptop,启动ubtuntu

    2024-07-10 11:12:05       26 阅读
  7. 达梦数据库主备手动切换

    2024-07-10 11:12:05       28 阅读
  8. ffmpeg滤镜创建过程

    2024-07-10 11:12:05       30 阅读