物联网操作系统学习笔记——系统互斥信号量

优先级翻转

什么是优先级翻转

互斥信号量概念及其应用

一、解决优先级翻转的问题
在这里插入图片描述
当高优先级任务去剥夺了低优先级任务的cpu使用权时,信号量如果被低优先级任务占有,高优先级任务处于阻塞态,临时提高低优先级任务的优先级。——互斥信号量的第一个特性
二值信号量一般用于信号同步
在这里插入图片描述
二值信号量主要做一些信号同步,任何一个任务都可以发送二值信号量,同时解除一个等待获取的任务的阻塞状态。1,只适合用于同步,2、二值信号量不是单个任务独有。

任务独占资源
在这里插入图片描述
互斥信号量的两个特性:
1、优先级继承
2、任务独占资源(这个资源是指什么资源?CPU使用权?)

FreeRTOS互斥信号量

在这里插入图片描述
mutex:常规信号量 ——隐患:会死锁
recursivemutex:递归的互斥信号量:解决死锁。

互斥信号量工作原理

在这里插入图片描述
递归互斥信号量解决死锁问题

在这里插入图片描述
普通互斥信号量锁死问题:当第一次使用互斥信号量的时候,如果再次使用互斥信号量,就相当于函数把自己挂起。互斥信号量只能在自己的任务中被使用被释放。调用两次就会一直处于阻塞状态。
递归互斥信号量解决死锁问题

互斥信号量函数应用

实验解决优先级翻转
功能需求:
在这里插入图片描述
API详解

xSemaphoreCreateMutex()
在这里插入图片描述

xSemaphoreGetMutexHolder()

在这里插入图片描述
递归互斥信号量函数应用
死锁现象:

2、API
xSemaphoreCreateRecursiveMutex()
在这里插入图片描述

xSemaphoreTakeRecursive()
在这里插入图片描述
xSemaphoreGiveRecursive()
在这里插入图片描述
实验验证()
在这里插入图片描述
在这里插入图片描述
使能USE_RECURSIVE_UTEXES()
在这里插入图片描述
创建递归信号量
高优先级任务

void High_Task(void const * argument)
{
  /* USER CODE BEGIN High_Task */
  /* Infinite loop */
  for(;;)
  {
	printf("High Task Take RecursiveMutex1\r\n");  
	 if(xSemaphoreTakeRecursive(myRecursiveMutexHandle,portMAX_DELAY) == pdPASS){
		printf("High Task is Runing\r\n");
	 }
	printf("High Task Take RecursiveMutex2\r\n");  
	 if(xSemaphoreTakeRecursive(myRecursiveMutexHandle,portMAX_DELAY) == pdPASS){
		printf("High Task is Runing\r\n");
	 }
	 printf("High Task Give RecursiveMutex1\r\n");  
	 xSemaphoreGiveRecursive(myRecursiveMutexHandle);
	 printf("High Task Give RecursiveMutex2\r\n");  
	 xSemaphoreGiveRecursive(myRecursiveMutexHandle);
    osDelay(500);
  }
  /* USER CODE END High_Task */
}

中等优先级任务

void Led_Task(void const * argument)
{

  /* USER CODE BEGIN Led_Task */
  /* Infinite loop */
  for(;;)
  {
	printf("Normal Task is Runing\r\n");
    osDelay(500);//1ms时基
  }
  /* USER CODE END Led_Task */
}

低优先级任务

void Delay_Task(void const * argument)
{
  /* USER CODE BEGIN Delay_Task */
	uint32_t i;
  /* Infinite loop */
  for(;;)
  {
	printf("Low Task Take RecursiveMutex\r\n");  
	 if(xSemaphoreTakeRecursive(myRecursiveMutexHandle,portMAX_DELAY) == pdPASS){
		printf("Low Task is Runing\r\n");
	 }
	 for(i=0;i<2000000;i++){
	 	 taskYIELD();
	 }
	 printf("Low Task Give RecursiveMutex\r\n");  
	 xSemaphoreGiveRecursive(myRecursiveMutexHandle);
    osDelay(500);
  }
  /* USER CODE END Delay_Task */
}

在这里插入图片描述

互斥信号量的原理

互斥信号量的创建
在这里插入图片描述
互斥信号量初始化
在这里插入图片描述

#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
	#define xSemaphoreCreateMutex()
	xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
#endif




	QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType )
	{
	Queue_t *pxNewQueue;
	const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0;
		//创建消息队列
		/*
			队列长度:1
			队列大小:0
			队列类型:queueQUEUE_TYPE_MUTEX
		*/
		pxNewQueue = ( Queue_t * ) xQueueGenericCreate( uxMutexLength, uxMutexSize, ucQueueType );
		//初始化互斥信号量->其实就是初始化消息队列的控制块
		prvInitialiseMutex( pxNewQueue );

		return pxNewQueue;
	}
	
	static void prvInitialiseMutex( Queue_t *pxNewQueue )
	{
		if( pxNewQueue != NULL )
		{
			/* 
				1.信号量的持有者为空
				2.消息队列的类型为互斥信号量
				3.递归记录初始为0
				4.往消息队列发送一个消息->其实赋值互斥信号量为1
			*/
			pxNewQueue->pxMutexHolder = NULL;
			pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;

			/* In case this is a recursive mutex. */
			pxNewQueue->u.uxRecursiveCallCount = 0;

			traceCREATE_MUTEX( pxNewQueue );

			/* Start with the semaphore in the expected state. */
			( void ) xQueueGenericSend( pxNewQueue, NULL, ( TickType_t ) 0U, queueSEND_TO_BACK );
		}
		else
		{
			traceCREATE_MUTEX_FAILED();
		}
	}

互斥信号量获取

在这里插入图片描述

//互斥信号量的获取

#define xSemaphoreTake( xSemaphore, xBlockTime )		
		xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )



BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking )
{
BaseType_t xEntryTimeSet = pdFALSE;
TimeOut_t xTimeOut;
int8_t *pcOriginalReadPosition;
Queue_t * const pxQueue = ( Queue_t * ) xQueue;


	#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;

			/* 判断等待处理的消息是否大于0 */
			if( uxMessagesWaiting > ( UBaseType_t ) 0 )
			{

				pcOriginalReadPosition = pxQueue->u.pcReadFrom;

				prvCopyDataFromQueue( pxQueue, pvBuffer );
				//队列不为空
				if( xJustPeeking == pdFALSE )
				{
					traceQUEUE_RECEIVE( pxQueue );

					/* Actually removing data, not just peeking. */
					pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1;
					/*
						1.判断是否为互斥信号量
						2.记录当前任务为信号量持有者
					*/
					#if ( configUSE_MUTEXES == 1 )
					{
						/*判断消息队列类型是否为互斥信号量*/
						if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
						{
							/* 2.记录当前任务为信号量持有者 */
							pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */
						}
						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 )
				{
					/* 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 )
				{
					/* The queue was empty and a block time was specified so
					configure the timeout structure. */
					vTaskSetTimeOutState( &xTimeOut );
					xEntryTimeSet = pdTRUE;
				}
				else
				{
					/* 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 );

		/* Update the timeout state to see if it has expired yet. */
		if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
		{
			if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
			{
				traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
				//队列为空处理
				/*
					1.是否为互斥信号量
					2.进入临界段
					3.优先级继承
				*/
				#if ( configUSE_MUTEXES == 1 )
				{
					if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
					{
						taskENTER_CRITICAL();
						{
							vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );//优先级继承
						}
						taskEXIT_CRITICAL();
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}
				#endif

				vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
				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();
			}
		}
	}
}

互斥信号量释放
在这里插入图片描述

#define xSemaphoreGive( xSemaphore )	
xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )

//互斥信号量处理在数据拷贝接口中
xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );

		/*
			1.判断是否为互斥信号量
			2.恢复任务优先级
			3.信号量持有者赋值为空,也就是说,其他任务可以获取了
		/*

		#if ( configUSE_MUTEXES == 1 )
		{
			if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
			{
				/* The mutex is no longer being held. */
				xReturn = xTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );
				pxQueue->pxMutexHolder = NULL;
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		#endif /* configUSE_MUTEXES */

记录互斥信号量持有者
在这里插入图片描述
任务优先级继承
在这里插入图片描述

//优先级继承原理

	void *pvTaskIncrementMutexHeldCount( void )
	{
		/* If xSemaphoreCreateMutex() is called before any tasks have been created
		then pxCurrentTCB will be NULL. */
		if( pxCurrentTCB != NULL )
		{
			//持有者任务控制块里的持有记录加一
			( pxCurrentTCB->uxMutexesHeld )++;
		}
		//返回当前任务控制块
		return pxCurrentTCB;
	}

#endif /* configUSE_MUTEXES */


//优先级继承
//重点是参数:持有互斥信号量的控制块
	void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder )
	{
	TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
		//判断任务控制块不为空
		if( pxMutexHolder != NULL )
		{
			/* 优先级小于当前获取的信号量的有限,才会去继承*/
			if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
			{
				/* Adjust the mutex holder state to account for its new
				priority.  Only reset the event list item value if the value is
				not	being used for anything else. */
				if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
				{
					//修改持有者事件列表中,列表项的属性值 为当前任务优先级
					listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}

				/* 
					4.判断持有者任务是否在就绪列表中
						4.1 移除
						4.2 修改任务优先级,这个修改是任务控制块里的信息
						4.3 添加到新的就绪列表中
				*/
				if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
				{
					if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
					{
						taskRESET_READY_PRIORITY( pxTCB->uxPriority );
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}

					/* Inherit the priority before being moved into the new list. */
					pxTCB->uxPriority = pxCurrentTCB->uxPriority;
					prvAddTaskToReadyList( pxTCB );
				}
				else
				{
					/* Just inherit the priority. */
					pxTCB->uxPriority = pxCurrentTCB->uxPriority;
				}

				traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority );
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}

#endif /* configUSE_MUTEXES */```

任务优先级恢复
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200908160747558.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9iYWlweWY=,size_16,color_FFFFFF,t_70#pic_center)

```c




		//优先级恢复

BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder )
	{
	TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
	BaseType_t xReturn = pdFALSE;

		if( pxMutexHolder != NULL )
		{
			//1、持有者任务持有记录减一
			( pxTCB->uxMutexesHeld )--;

			/* Has the holder of the mutex inherited the priority of another
			task? */
			//2、优先级是否修改过
			if( pxTCB->uxPriority != pxTCB->uxBasePriority )
			{	
				//3、递归记录为0的时候
				/* Only disinherit if no other mutexes are held. */
				if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 )
				{
					/* 4、从当前的就绪列表中移除 */
					if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
					{
						taskRESET_READY_PRIORITY( pxTCB->uxPriority );
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}

					/* 5、恢复任务优先级 */
					traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
					pxTCB->uxPriority = pxTCB->uxBasePriority;

					/* 6、已经不是持有者,把任务添加到新的就绪列表中去 */
					listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
					prvAddTaskToReadyList( pxTCB );

					/* 7、触发上下文切换,释放CPU的使用权 */
					xReturn = pdTRUE;
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}

		return xReturn;
	}

#endif /* configUSE_MUTEXES */

递归信号量的获取
在这里插入图片描述

#if( configUSE_RECURSIVE_MUTEXES == 1 )
	#define xSemaphoreTakeRecursive( xMutex, xBlockTime )	
	xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )
#endif
/*
	参数:互斥信号量句柄,超时等待时间

*/
BaseType_t xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait )
	{
	BaseType_t xReturn;
	Queue_t * const pxMutex = ( Queue_t * ) xMutex;


		//判断是否为持有者
		/*
			如果为持有者
				递归记录加一
				返回成功
		*/
		if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */
		{
			( pxMutex->u.uxRecursiveCallCount )++;
			xReturn = pdPASS;
		}
		/*
			不为持有者
				接收消息----获取信号量
				获取成功----递归记录加一
				获取失败----返回错误
		*/
		else
		{
			xReturn = xQueueGenericReceive( pxMutex, NULL, xTicksToWait, pdFALSE );


			if( xReturn != pdFAIL )
			{
				( pxMutex->u.uxRecursiveCallCount )++;
			}
			else
			{
				traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex );
			}
		}

		return xReturn;
	}

#endif /* configUSE_RECURSIVE_MUTEXES */

递归互斥信号量释放

在这里插入图片描述

#if( configUSE_RECURSIVE_MUTEXES == 1 )
	#define xSemaphoreGiveRecursive( xMutex )	
xQueueGiveMutexRecursive( ( xMutex ) )
#endif

/*
	参数:
		信号量句柄
	步骤:
		1、判断当前任务是否为持有者
			1.1、递归记录减一
			1.2、判断记录是否为0
			1.3、发送一个消息
		2、不为持有者返回错误
		


*/

	BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex )
	{
	BaseType_t xReturn;
	Queue_t * const pxMutex = ( Queue_t * ) xMutex;

		
		if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 Not a redundant cast as TaskHandle_t is a typedef. */
		{

			( pxMutex->u.uxRecursiveCallCount )--;

			/* */
			if( pxMutex->u.uxRecursiveCallCount == ( UBaseType_t ) 0 )
			{
				/*  */
				( void ) xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK );
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}

			xReturn = pdPASS;
		}
		else
		{
			/* */
			xReturn = pdFAIL;

		}

		return xReturn;
	}

#endif /* configUSE_RECURSIVE_MUTEXES */
/*

版权声明:本文为xiaobaipyf原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。