freeRTOS 信号量:二值 计数 互斥 递归互斥

用于信号量的队列,都是只有队列数据结构的空间,没有队列项存储空间的队列。

二值、计数、互斥、递归互斥,创建完成之后的内存状态:(转自 http://blog.csdn.net/zhzht19861011/article/details/51537234)

 

 

 

一、创建二值信号量

/**
 * semphr. h
 * SemaphoreHandle_t xSemaphoreCreateBinary( void )
 * 
 * Creates a new binary semaphore instance, and returns a handle by which the
 * new semaphore can be referenced.
 * 
 * <i>Macro</i> that implements a semaphore by using the existing queue mechanism.
 * The queue length is 1 as this is a binary semaphore.  The data size is 0 as we don't want to actually store any data - 
* we just want to know if the queue is empty or full. */ #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH(=0), queueQUEUE_TYPE_BINARY_SEMAPHORE(类型) ) #endif

hint: QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType )

只关注这个队列是否为满,判断 uxMsgWaiting 即可。(只有队列数据结构的空间,没有队列项存储空间的队列)

volatile UBaseType_t uxMessagesWaiting;  /*< The number of items currently in the queue. */   item数量

二、释放信号量(入队)

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

hint: BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition )


  #define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken )       xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), ( pxHigherPriorityTaskWoken ) )

  绝对不能,用此函数Give互斥信号量!  互斥信号量涉及到优先级继承,不能在中断中获取和释放...

三、获取信号量(出队)

#define xSemaphoreTake( xSemaphore, xBlockTime )        xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )
hint: BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking )


  #define xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken )       xQueueReceiveFromISR( ( QueueHandle_t ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ) )

  同样的,绝对不能,用此函数Take互斥信号量!  互斥信号量涉及到优先级继承,不能在中断中获取和释放...

 

 

 

 

===========================================================

创建计数型信号量

#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount )     xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )


    QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount )
    {
    QueueHandle_t xHandle;

        configASSERT( uxMaxCount != 0 );
        configASSERT( uxInitialCount <= uxMaxCount );

        xHandle = xQueueGenericCreate( uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH(=0), queueQUEUE_TYPE_COUNTING_SEMAPHORE(类型) );  

        if( xHandle != NULL )
        {
            ( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount;  使用uxMsgWaiting计数,这里是初始化赋值。

            traceCREATE_COUNTING_SEMAPHORE();
        }
        else
        {
            traceCREATE_COUNTING_SEMAPHORE_FAILED();
        }

        return xHandle;
    }

Give和Take,同上。

 

 

 

 

===========================================================

互斥信号量

优先级继承并不能完全的消除优先级翻转, 它只是尽可能的降低优先级翻转带来的影响。 【因为毕竟高优先级的任务确实是被耽搁了】

互斥信号量不能用于中断服务函数中,原因如下:

1. 互斥信号量有优先级继承的机制,所以只能用在任务中,不能用于中断服务函数。

2. 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。 xSemaphoreTake( xSemaphore, xBlockTime )

 

一、创建互斥信号量

SemaphoreHandle_t xSemaphoreCreateMutex( void )
#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
#if( ( configUSE_MUTEXES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )

QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType )
{
  Queue_t *pxNewQueue;
  const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0;  队列长度1,item长度0

  pxNewQueue = ( Queue_t * ) xQueueGenericCreate( uxMutexLength, uxMutexSize, ucQueueType ); 类型应该是queueQUEUE_TYPE_MUTEX   prvInitialiseMutex( pxNewQueue );   return pxNewQueue; } #endif /* configUSE_MUTEXES */
   static void prvInitialiseMutex( Queue_t *pxNewQueue )
    {
        if( pxNewQueue != NULL )
        {
            /* The queue create function will set all the queue structure members
            correctly for a generic queue, but this function is creating a
            mutex.  Overwrite those members that need to be set differently -
            in particular the information required for priority inheritance. */
队列创建的时候会初始化队列,但这里需要重新赋值,尤其和优先级继承相关的。 pxNewQueue->pxMutexHolder = NULL; pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX; /* In case this is a recursive mutex. */ pxNewQueue->u.uxRecursiveCallCount = 0; 专门用于,递归互斥信号量(跟u.readFrom指针占一个空间) 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 pxMutexHolder pcTail
#define uxQueueType pcHead
#define queueQUEUE_IS_MUTEX NULL
当用于互斥信号量的时候将
pcHead(
uxQueueType指向 NULL
pcTail(pxMutexHolder) 指向 TCB,拥有互斥信号量的任务的任务控制块。

 

二、释放互斥信号量

释放互斥信号量的时候和二值信号量、计数型信号量一样,都是用的函数 xSemaphoreGive()(实际上完成信号量释放的是函数 xQueueGenericSend())

使用函数 xSemaphoreGive()释放信号量最重要的一步就是uxMessagesWaiting加一, 和优先级继承,这两个都是在函数 prvCopyDataToQueue()中完成的。

QueueGenericSend  调用  CopyDataToQueue.

 1 static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition )
 2 {
 3 BaseType_t xReturn = pdFALSE;
 4 UBaseType_t uxMessagesWaiting;
 5 
 6     /* This function is called from a critical section. */
 7 
 8     uxMessagesWaiting = pxQueue->uxMessagesWaiting;
 9 
10     if( pxQueue->uxItemSize == ( UBaseType_t ) 0 )  队列item长度为0,专为信号量设计。
11     {
12         #if ( configUSE_MUTEXES == 1 )  互斥信号量
13         {
14             if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
15             {
16                 /* The mutex is no longer being held. */
17                 xReturn = xTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );   处理优先级继承问题!
18                 pxQueue->pxMutexHolder = NULL;  互斥量释放后,就不属于任何任务了,所以Holder指向NULL.
19             }
20             else
21             {
22                 mtCOVERAGE_TEST_MARKER();
23             }
24         }
25         #endif /* configUSE_MUTEXES */
26     }
27     else if( xPosition == queueSEND_TO_BACK )  加入到队列最后
28     {
29         ( void ) memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 */
30         pxQueue->pcWriteTo += pxQueue->uxItemSize;
31         if( pxQueue->pcWriteTo >= pxQueue->pcTail ) /*lint !e946 */
32         {
33             pxQueue->pcWriteTo = pxQueue->pcHead;
34         }
35         else
36         {
37             mtCOVERAGE_TEST_MARKER();
38         }
39     }
40     else  加入到队列最前
41     {
42         ( void ) memcpy( ( void * ) pxQueue->u.pcReadFrom, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 */
43         pxQueue->u.pcReadFrom -= pxQueue->uxItemSize;
44         if( pxQueue->u.pcReadFrom < pxQueue->pcHead ) /*lint !e946 */
45         {
46             pxQueue->u.pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );
47         }
48         else
49         {
50             mtCOVERAGE_TEST_MARKER();
51         }
52 
53         if( xPosition == queueOVERWRITE )  覆盖写入,统计item数量值自减。
54         {
55             if( uxMessagesWaiting > ( UBaseType_t ) 0 )
56             {
57                 /* An item is not being added but overwritten, so subtract
58                 one from the recorded number of items in the queue so when
59                 one is added again below the number of recorded items remains
60                 correct. */
61                 --uxMessagesWaiting;
62             }
63             else
64             {
65                 mtCOVERAGE_TEST_MARKER();
66             }
67         }
68         else
69         {
70             mtCOVERAGE_TEST_MARKER();
71         }
72     }
73 
74     pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1;  重点变量
75 
76     return xReturn;
77 }
 1 #if ( configUSE_MUTEXES == 1 )
 2 
 3     BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder )
 4     {
 5     TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
 6     BaseType_t xReturn = pdFALSE;
 7 
 8         if( pxMutexHolder != NULL )  Holder表示拥有此互斥量的TCB,先判断其是否被其他任务获取。
 9         {
10             /* A task can only have an inherited priority if it holds the mutex.
11             If the mutex is held by a task then it cannot be given from an
12             interrupt, and if a mutex is given by the holding task then it must
13             be the running state task. */
14             configASSERT( pxTCB == pxCurrentTCB );  读上边英文
15 
16             configASSERT( pxTCB->uxMutexesHeld );  uxMutexesHeld保存当前任务获取到的互斥量的个数,可能获取多个互斥量
17             ( pxTCB->uxMutexesHeld )--;
18 
19             /* Has the holder of the mutex inherited the priority of another
20             task? */
21             if( pxTCB->uxPriority != pxTCB->uxBasePriority )  是否存在优先级继承,如果存在,那么任务当下的Prio和任务的BasePrio肯定不同!
22             {
23                 /* Only disinherit if no other mutexes are held. */  当前任务只获取了一个互斥量
24                 if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 )
25                 {
26                     /* A task can only have an inherited priority if it holds
27                     the mutex.  If the mutex is held by a task then it cannot be
28                     given from an interrupt, and if a mutex is given by the
29                     holding    task then it must be the running state task.  Remove
30                     the    holding task from the ready    list. */
判断当前释放的是不是任务所获取的最后一个互斥量,优先级继承的处理,必须是在“释放最后一个互斥量时”。
31 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
32 {
33 taskRESET_READY_PRIORITY( pxTCB->uxPriority ); 如果继承来的这个优先级,没有其他就绪任务,清除这个优先级的就绪态(TopReadyPrio变量)
34 }
35 else
36 {
37 mtCOVERAGE_TEST_MARKER();
38 }
40                     /* Disinherit the priority before adding the task into the
41                     new    ready list. */  使用新优先级(BasePrio),将任务加入到就绪列表。
42                     traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
43                     pxTCB->uxPriority = pxTCB->uxBasePriority;    重新设置为BasePrio.
44 
45                     /* Reset the event list item value. 重置事件列表项的值 It cannot be in use for
46                     any other purpose if this task is running, and it must be
47                     running to give back归还 the mutex. */  这个列表的排放顺序是,跟优先级的数值反着来的哦!【优先级数越小越低】
48                     listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority ); /*lint !e961 */
49                     prvAddTaskToReadyList( pxTCB );   优先级恢复后,任务加到BasePrio的就绪表.
50 
51                     /* Return true to indicate that a context switch is required.
52                     This is only actually required in the corner case whereby
53                     multiple mutexes were held and the mutexes were given back
54                     in an order different to that in which they were taken.
55                     If a context switch did not occur when the first mutex was
56                     returned, even if a task was waiting on it,/ then那么 a context
57                     switch should必须 occur when the last mutex is returned whether
58                     a task is waiting on it or not. */
59                     xReturn = pdTRUE;  //return ture表示需要任务切换
60                 }
61                 else
62                 {
63                     mtCOVERAGE_TEST_MARKER();
64                 }
65             }
66             else
67             {
68                 mtCOVERAGE_TEST_MARKER();
69             }
70         }
71         else
72         {
73             mtCOVERAGE_TEST_MARKER();
74         }
75 
76         return xReturn;
77     }
78 
79 #endif /* configUSE_MUTEXES */

简化为两种情况:

第一,如果队列未满,除了队列结构体成员uxMessageWaiting加1外,还要判断获取互斥量的任务是否有优先级继承,

如果有的话,还要将任务的优先级恢复到原始值,操作任务状态所在的队列等。

当然,恢复到原来值也是有条件的,就是该任务必须在没有使用其它互斥量的情况下,才能将继承的优先级恢复到原始值。

然后数据入队成功,判断是否有阻塞的任务,有的话解除阻塞,最后返回成功信息(pdPASS);

第二,如果如果队列满,返回错误代码(err_QUEUE_FULL),表示队列满。

 

 

 

三、获取互斥信号量

获取互斥量的函数同获取二值信号量和计数型信号量的函数相同,都是 xSemaphoreTake( xSemaphore, xBlockTime )(实际执行信号量获取的函数是 xQueueGenericReceive())

获取互斥信号量的过程也需要处理优先级继承的问题。

  1 BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking )
  2 {
  3 BaseType_t xEntryTimeSet = pdFALSE;
  4 TimeOut_t xTimeOut;
  5 int8_t *pcOriginalReadPosition;
  6 Queue_t * const pxQueue = ( Queue_t * ) xQueue;
  7 
  8     configASSERT( pxQueue );
  9     configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) );
 10     #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
 11     {
 12         configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
 13     }
 14     #endif
 15 
 16     /* This function relaxes the coding standard somewhat to allow return
 17     statements within the function itself.  This is done in the interest
 18     of execution time efficiency. */
 19 
 20     for( ;; )
 21     {
 22         taskENTER_CRITICAL();
 23         {
 24             const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;
 25 
 26             /* Is there data in the queue now?  To be running the calling task
 27             must be the highest priority task wanting to access the queue. */
 28             if( uxMessagesWaiting > ( UBaseType_t ) 0 )  判断队列是否有消息
 29             {
 30                 /* Remember the read position in case the queue is only being
 31                 peeked. */
 32                 pcOriginalReadPosition = pxQueue->u.pcReadFrom;
 33 
 34                 prvCopyDataFromQueue( pxQueue, pvBuffer );
 35 
 36                 if( xJustPeeking == pdFALSE )  【非peek读取】
 37                 {
 38                     traceQUEUE_RECEIVE( pxQueue );
 39 
 40                     /* Actually removing data, not just peeking. */
 41                     pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1;
 42 
 43                     #if ( configUSE_MUTEXES == 1 )
 44                     {
 45                         if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )  队列类型是互斥量
 46                         {
 47                             /* Record the information required to implement
 48                             priority inheritance should it become necessary. */
 49                             pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); /*lint !e961 */
                                holder是当前任务的TCB,
函数TaskIncrementMutexHeldCnt只是把MutexHeld加一,表示任务获取了一个互斥量,这个函数返回当前任务的TCB
50 } 51 else 52 { 53 mtCOVERAGE_TEST_MARKER(); 54 } 55 } 56 #endif /* configUSE_MUTEXES */ 57 58 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) 出队成功,判断是否"有任务入队阻塞" 59 { 60 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) 61 { 62 queueYIELD_IF_USING_PREEMPTION(); 解除阻塞任务的优先级比当前任务高,需要进行任务切换。 63 } 64 else 65 { 66 mtCOVERAGE_TEST_MARKER(); 67 } 68 } 69 else 70 { 71 mtCOVERAGE_TEST_MARKER(); 72 } 73 } 74 else 【peek读取】 75 { 76 traceQUEUE_PEEK( pxQueue ); 77 78 /* The data is not being removed, so reset the read 79 pointer. */ 80 pxQueue->u.pcReadFrom = pcOriginalReadPosition; 重置读指针,刚刚出队的消息仍然有效。 81 82 /* The data is being left in the queue, so see if there are 83 any other tasks waiting for the data. */ 84 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) 消息仍然有效,判断是否有任务因为出队阻塞 85 { 86 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) 87 { 88 /* The task waiting has a higher priority than this task. */ 89 queueYIELD_IF_USING_PREEMPTION(); 同样的解除阻塞的prio高于当前任务,则切换任务。 90 } 91 else 92 { 93 mtCOVERAGE_TEST_MARKER(); 94 } 95 } 96 else 97 { 98 mtCOVERAGE_TEST_MARKER(); 99 } 100 } 101 102 taskEXIT_CRITICAL(); 103 return pdPASS; 104 } 105 else 【队列为空】 106 { 107 if( xTicksToWait == ( TickType_t ) 0 ) 阻塞时间0,直接返回 errQUEUE_EMPTY 108 { 109 /* The queue was empty and no block time is specified (or 110 the block time has expired) so leave now. */ 111 taskEXIT_CRITICAL(); 112 traceQUEUE_RECEIVE_FAILED( pxQueue ); 113 return errQUEUE_EMPTY; 114 } 115 else if( xEntryTimeSet == pdFALSE ) 阻塞时间不为零,初始化时间状态结构体 116 { 117 /* The queue was empty and a block time was specified so 118 configure the timeout structure. */ 119 vTaskSetTimeOutState( &xTimeOut ); 120 xEntryTimeSet = pdTRUE; 121 } 122 else 123 { 124 /* Entry time was already set. */ 125 mtCOVERAGE_TEST_MARKER(); 126 } 127 } 128 } 129 taskEXIT_CRITICAL(); 130 131 /* Interrupts and other tasks can send to and receive from the queue 132 now the critical section has been exited. */ 133 134 vTaskSuspendAll(); 135 prvLockQueue( pxQueue ); 136 137 /* Update the timeout state to see if it has expired yet. */ 更新时间状态结构体,并且检查超时是否发生。 138 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) 超时没有发生 139 { 140 if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) 【队列为空】 141 { 142 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); 143 144 #if ( configUSE_MUTEXES == 1 ) 145 { 146 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) 是互斥量 147 { 148 taskENTER_CRITICAL(); 149 { 150 vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); 调用函数处理优先级继承问题。
执行到这里说明互斥量正在被其他任务占用。
TaskPrioInherit函数与TaskPrioDisinherit()过程相反:
此函数会判断当前任务的Prio是否比正拥有互斥量的任务Prio高,如果高,就会把拥有互斥量的那个低Prio任务调整为与当前任务相同的优先级。 151 } 152 taskEXIT_CRITICAL(); 153 } 154 else 155 { 156 mtCOVERAGE_TEST_MARKER(); 157 } 158 } 159 #endif 160 161 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); 将任务添加到WaitToRcv列表。 162 prvUnlockQueue( pxQueue ); 163 if( xTaskResumeAll() == pdFALSE ) 164 { 165 portYIELD_WITHIN_API(); 166 } 167 else 168 { 169 mtCOVERAGE_TEST_MARKER(); 170 } 171 } 172 else 【队列不为空】 173 { 174 /* Try again. */ 重试一次 175 prvUnlockQueue( pxQueue ); 176 ( void ) xTaskResumeAll(); 177 } 178 } 179 else 【超时了】 180 { 181 prvUnlockQueue( pxQueue ); 182 ( void ) xTaskResumeAll(); 183 184 if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) 队列还是空的 185 { 186 traceQUEUE_RECEIVE_FAILED( pxQueue ); 187 return errQUEUE_EMPTY; 返回队列空! 188 } 189 else 190 { 191 mtCOVERAGE_TEST_MARKER(); 192 } 193 } 194 } 195 }

互斥信号量,任务中必须具有take和give成对出现。(解决优先级继承)

 

 

 

 

===========================================================

一、递归互斥量

  已经获取了递归互斥信号量的任务可以再次获取这个递归互斥信号量,而且次数不限!

一个任务使用函数 xSemaphoreTakeRecursive()成功的获取了多少次递归互斥信号量,

就得使用函数 xSemaphoreGiveRecursive()释放多少次。

  递归互斥信号量也有优先级继承的机制,所以当任务使用完递归互斥信号量以后一定要释放。

同互斥信号量一样,递归互斥信号量不能用在中断服务函数中。

1. 互斥信号量有优先级继承的机制,所以只能用在任务中,不能用于中断服务函数。

2. 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。 xSemaphoreTakeRecursive( xMutex, xBlockTime )

一、创建

SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )
#define   xSemaphoreCreateRecursiveMutex()    xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX )
创建过程和互斥量一样,类型选择为 queueQUEUE_TYPE_RECURSIVE_MUTEX。

 

二、释放

#define xSemaphoreGiveRecursive( xMutex )    xQueueGiveMutexRecursive( ( xMutex ) )

#if ( configUSE_RECURSIVE_MUTEXES == 1 )

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

        configASSERT( pxMutex );

        /* If this is the task that holds the mutex then pxMutexHolder will not
        change outside of this task.  If this task does not hold the mutex then
        pxMutexHolder can never coincidentally equal the tasks handle, and as
        this is the only condition we are interested in it does not matter if
        pxMutexHolder is accessed simultaneously by another task.  Therefore no
        mutual exclusion is required to test the pxMutexHolder variable. */
检查递归互斥量是不是被当前任务获取的,要释放递归互斥量的任务肯定是当前运行的任务。
和互斥量一样,Take和Give要在同一个任务中完成!
如果当前正在运行的任务不是递归互斥量的拥有者,就不能释放! if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 */ { traceGIVE_MUTEX_RECURSIVE( pxMutex ); /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to the task handle, therefore no underflow check is required. Also, uxRecursiveCallCount is only modified by the mutex holder, and as there can only be one, no mutual exclusion is required to modify the uxRecursiveCallCount member. */
CallCnt记录被Take的次数,
多次Take多次Give的实现:
Give的时候只在最后一次调用xQueueGenericSend(),其他时候只是简单的将CallCnt减一。 ( pxMutex
->u.uxRecursiveCallCount )--; /* Has the recursive call count unwound to 0? */ if( pxMutex->u.uxRecursiveCallCount == ( UBaseType_t ) 0 ) 是最后一次释放了。 { /* Return the mutex. This will automatically unblock any other task that might be waiting to access the mutex. */ ( void ) xQueueGenericSend( pxMutex, NULL,
queueMUTEX_GIVE_BLOCK_TIME(=0), queueSEND_TO_BACK ); }
else { mtCOVERAGE_TEST_MARKER(); } xReturn = pdPASS; Give成功 } else { /* The mutex cannot be given because the calling task is not the holder. */ xReturn = pdFAIL; Give失败 traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ); } return xReturn; } #endif /* configUSE_RECURSIVE_MUTEXES */

 

三、获取

#define xSemaphoreTakeRecursive( xMutex, xBlockTime )    xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )

#if ( configUSE_RECURSIVE_MUTEXES == 1 )

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

        configASSERT( pxMutex );

        /* Comments regarding mutual exclusion as per those within
        xQueueGiveMutexRecursive(). */

        traceTAKE_MUTEX_RECURSIVE( pxMutex );

判断当前要Take递归量的任务是不是已经是Hodler,通过这一步判断当前任务是第一次Take还是重复Take。
if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 */ { ( pxMutex->u.uxRecursiveCallCount )++; 本次是重复Take,就简单的CallCnt加一 xReturn = pdPASS; 返回Take成功 } else { xReturn = xQueueGenericReceive( pxMutex, NULL, xTicksToWait, pdFALSE ); 第一次Take的话,完成真正的Take过程! /* pdPASS will only be returned if the mutex was successfully obtained. The calling task may have entered the Blocked state before reaching here. */ if( xReturn != pdFAIL ) { ( pxMutex->u.uxRecursiveCallCount )++; 第一次Take成功后,CallCnt加一 } else { traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex ); } } return xReturn; } #endif /* configUSE_RECURSIVE_MUTEXES */

任务获取了三次递归互斥信号量,所以就得释放三次!

递归互斥信号量释放完成后,可以被其他任务获取。

 

 

 

 

这两个API不能给互斥量用(只能二值、计数型):
xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken )
xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken )



这两个API通用(二值、计数型、互斥):
xSemaphoreGive( xSemaphore )
xSemaphoreTake( xSemaphore, xBlockTime ) 



专门给递归量用:
xSemaphoreGiveRecursive( xMutex ) 
xSemaphoreTakeRecursive( xMutex, xBlockTime ) 

 

 

 

 

 

留白

posted @ 2017-11-20 21:04  为民除害  阅读(2709)  评论(0编辑  收藏  举报