freeRtos中读队列函数xQueueGenericReceive解析

BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking )
{  //出队:xQueue:操作的队列的句柄 pvBuffer:缓冲区 xTicksToWait:等待时间 xJustPeeking:是不是要删除数据
	BaseType_t xEntryTimeSet = pdFALSE;
	TimeOut_t xTimeOut;
	int8_t *pcOriginalReadPosition;
	Queue_t * const pxQueue = ( Queue_t * ) xQueue;

	configASSERT( pxQueue );
	configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) );
	#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
	{
		configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
	}
	#endif

	/* This function relaxes the coding standard somewhat to allow return
	statements within the function itself.  This is done in the interest
	of execution time efficiency. */

	for( ;; )
	{
		taskENTER_CRITICAL();  //进入临界区
		{
			const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; //uxMessagesWaiting储存队列中的数据数量

			/* Is there data in the queue now?  To be running the calling task
			must be the highest priority task wanting to access the queue. */
			if( uxMessagesWaiting > ( UBaseType_t ) 0 )  //如果队列中有数据
			{
				/* Remember the read position in case the queue is only being
				peeked. */
				pcOriginalReadPosition = pxQueue->u.pcReadFrom;  //记录读取队列的位置

				prvCopyDataFromQueue( pxQueue, pvBuffer ); //将数据拷贝到缓冲区中

				if( xJustPeeking == pdFALSE ) //如果读取后需要删除掉
				{
					traceQUEUE_RECEIVE( pxQueue );

					/* Actually removing data, not just peeking. */
					pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1; //将队列中数据数量减一

					#if ( configUSE_MUTEXES == 1 )  //如果是互斥信号量
					{
						if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) //如果是互斥信号量
						{
							/* Record the information required to implement
							priority inheritance should it become necessary. */
							pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */
						}   //标记谁获取了互斥信号量的钥匙,并且将此任务的uxMutexesHeld加1
						    //uxMutexesHeld表示任务拥有互斥信号量的钥匙的数量,一个任务可能获取多个互斥信号量
						else 
						{
							mtCOVERAGE_TEST_MARKER();
						}
					}
					#endif /* configUSE_MUTEXES */

					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
					{ //出队之后看是不是有没有任务等待入队而阻塞
						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
						{ //有阻塞的任务的话将此任务解除从阻塞列表中移除,并判断是不是要进行任务切换
							queueYIELD_IF_USING_PREEMPTION();
						}
						else
						{
							mtCOVERAGE_TEST_MARKER();
						}
					}
					else //没有任务在等待写队列直接退出
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}
				else  //读取数据后不需要删除
				{
					traceQUEUE_PEEK( pxQueue );

					/* The data is not being removed, so reset the read
					pointer. */
					pxQueue->u.pcReadFrom = pcOriginalReadPosition; //重置读取队列的位置

					/* The data is being left in the queue, so see if there are
					any other tasks waiting for the data. */
					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
					{ //判断是不是有任务等待出队而阻塞
						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
						{ //有任务阻塞的话就将此任务从阻塞列表中移除并判断是不是要进行任务切换
							/* The task waiting has a higher priority than this task. */
							queueYIELD_IF_USING_PREEMPTION();
						}
						else
						{
							mtCOVERAGE_TEST_MARKER();
						}
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}

				taskEXIT_CRITICAL();  //退出临界区
				return pdPASS;        //返回成功表示读取队列成功
			}
			else  //如果队列中没有数据
			{
				if( xTicksToWait == ( TickType_t ) 0 ) //如果等待时间为0表示不等待
				{
					/* The queue was empty and no block time is specified (or
					the block time has expired) so leave now. */
					taskEXIT_CRITICAL();                      //不等待的话直接退出
					traceQUEUE_RECEIVE_FAILED( pxQueue );
					return errQUEUE_EMPTY;                    //返回队列空
				}
				else if( xEntryTimeSet == pdFALSE )           //等待时间不为0的情况下如果时间结构体没有初始化
				{
					/* The queue was empty and a block time was specified so
					configure the timeout structure. */
					vTaskSetTimeOutState( &xTimeOut );        //初始化时间结构体
					xEntryTimeSet = pdTRUE;
				}
				else                                          //等待时间不为0并且时间结构体已经初始化
				{
					/* Entry time was already set. */
					mtCOVERAGE_TEST_MARKER();                 //继续操作
				}
			}
		}
		taskEXIT_CRITICAL();                                  //退出临界区

		/* Interrupts and other tasks can send to and receive from the queue
		now the critical section has been exited. */

		vTaskSuspendAll();                       //暂停任务调度并给队列上锁
		prvLockQueue( pxQueue );                 //执行到这里说明队列不是空的并且等待时间不是0

		/* Update the timeout state to see if it has expired yet. */
		if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) //检查是否超时,返回pdFALSE表示还没超过
		{                                                                 //没超过的话就将任务添加到xTasksWaitingToReceive列表中
			if( prvIsQueueEmpty( pxQueue ) != pdFALSE )                   //如果队列是空的
			{
				traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );

				#if ( configUSE_MUTEXES == 1 )  //表示这是互斥信号量
				{
					if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) //判断队列是不是互斥信号量
					{
						taskENTER_CRITICAL();  //是互斥的话,进入临界区
						{
							vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );  //执行到这里说明队列是空的也就是
							                                                            //互斥信号量的钥匙在其他任务那里
																						//vTaskPriorityInherit用于判断当前任务的优先级
																						//是否比拥有钥匙的那个任务的优先级高
																						//如果是则进行优先级继承使拥有钥匙的任务尽快完成归还钥匙
																						//从而避免优先级反转的情况
						}
						taskEXIT_CRITICAL();  //退出临界区
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}
				#endif

				vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
				//队列是空的所以要将等待的任务添加到xTasksWaitingToReceive列表中
				prvUnlockQueue( pxQueue ); //解锁队列
				if( xTaskResumeAll() == pdFALSE )
				{
					portYIELD_WITHIN_API();  //任务切换
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{ //队列不是空的就解锁队列再试一次
				/* Try again. */
				prvUnlockQueue( pxQueue );
				( void ) xTaskResumeAll();
			}
		}
		else //等待时间超过了直接返回
		{
			prvUnlockQueue( pxQueue );
			( void ) xTaskResumeAll();

			if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
			{
				traceQUEUE_RECEIVE_FAILED( pxQueue );
				return errQUEUE_EMPTY;
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
	}
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FreeRTOS中的队列是一种用于任务之间通信的机制。它允许任务在队列中发送和接收数据项目。队列可以用于任务与任务之间的通信,也可以用于任务与中断之间的通信。队列中可以存储有限的、大小固定的数据项目。 要使用FreeRTOS中的队列,首先需要创建一个队列对象,并指定数据项目的大小和队列的长度。然后,任务可以使用队列的API函数将数据项目发送到队列中,或从队列中接收数据项目。 在向队列发送数据之前,任务通常需要检查队列是否已满。如果队列已满,则无法发送数据。当队列未满或者是覆写入队列时,任务可以将消息入队。 以下是一个示例代码,演示了如何在FreeRTOS中使用队列: ```c #include "FreeRTOS.h" #include "task.h" #include "queue.h" // 定义队列长度和数据项目大小 #define QUEUE_LENGTH 5 #define ITEM_SIZE sizeof(int) // 创建队列句柄 QueueHandle_t queueHandle; // 任务1,向队列发送数据 void Task1(void *pvParameters) { int data = 123; while (1) { // 检查队列是否已满 if (uxQueueSpacesAvailable(queueHandle) > 0) { // 发送数据到队列 xQueueSend(queueHandle, &data, 0); } vTaskDelay(pdMS_TO_TICKS(1000)); } } // 任务2,从队列接收数据 void Task2(void *pvParameters) { int receivedData; while (1) { // 从队列接收数据 if (xQueueReceive(queueHandle, &receivedData, portMAX_DELAY) == pdTRUE) { // 处理接收到的数据 // ... } vTaskDelay(pdMS_TO_TICKS(1000)); } } int main(void) { // 创建队列 queueHandle = xQueueCreate(QUEUE_LENGTH, ITEM_SIZE); // 创建任务1和任务2 xTaskCreate(Task1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL); xTaskCreate(Task2, "Task2", configMINIMAL_STACK_SIZE, NULL, 2, NULL); // 启动调度器 vTaskStartScheduler(); return 0; } ``` 在上面的示例中,任务1通过调用`xQueueSend`函数将数据发送到队列中,任务2通过调用`xQueueReceive`函数队列中接收数据。任务1在发送数据之前会检查队列是否已满,以确保数据能够成功发送。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值