zoukankan      html  css  js  c++  java
  • 关于FreeRTOS的信号量、队列

    FreeRTOS的队列是基础,其它的,比如信号量等都是基于队列实现的。

    1 #define queueQUEUE_TYPE_BASE                ( 0U )
    2 #define queueQUEUE_TYPE_MUTEX                 ( 1U )
    3 #define queueQUEUE_TYPE_COUNTING_SEMAPHORE    ( 2U )
    4 #define queueQUEUE_TYPE_BINARY_SEMAPHORE    ( 3U )
    5 #define queueQUEUE_TYPE_RECURSIVE_MUTEX        ( 4U )

    信号量包括二值信号量、计数信号量、递归信号量、互斥信号量(Mutex: Mut + Exclusion)。

    对于二值信号量,对存在优先级反转的问题。

    比如任务3、2、1的优先级从高到低,任务3和1通过二值信号量控制访问某个资源,若任务1先锁定该资源,则任务3访问该资源时,会因为得不到资源而阻塞。此时,若任务2运行条件具备,任务2会打断任务1而执行,从而呈现低优先级的任务2优先于高优先级的任务3运行的情景,即优先级反转了。

    由于二值信号量的这个问题,于是有了互斥信号量,互斥信号量与二值信号量的区别在于,互斥信号量具有优先级继承的特性。即在任务3获取互斥信号量的时候,若无法获取互斥信号量,则会判断一下当前获取互斥信号量的任务优先级是否比自己低,若是,则将该任务的优先级提高到和自己一样。

    queue定义如下,头pcHead和尾pcTail均为指向字节量,pcWriteTo指向第一个成员地址,pcReadFrom指向最后一个成员地址,xTasksWaitingToSend等待向队列发送数据的任务列表,该任务同时也会在挂起(等待时间为无限)或延时列表(等待时间为有限)中。uxMessagesWaiting队列成员个数,虽然名字有个waiting。

     1 typedef struct QueueDefinition
     2 {
     3     signed char *pcHead;                /*< Points to the beginning of the queue storage area. */
     4     signed char *pcTail;                /*< Points to the byte at the end of the queue storage area.  Once more byte is allocated than necessary to store the queue items, this is used as a marker. */
     5 
     6     signed char *pcWriteTo;                /*< Points to the free next place in the storage area. */
     7     signed char *pcReadFrom;            /*< Points to the last place that a queued item was read from. */
     8 
     9     xList xTasksWaitingToSend;                /*< List of tasks that are blocked waiting to post onto this queue.  Stored in priority order. */
    10     xList xTasksWaitingToReceive;            /*< List of tasks that are blocked waiting to read from this queue.  Stored in priority order. */
    11 
    12     volatile unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */
    13     unsigned portBASE_TYPE uxLength;        /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
    14     unsigned portBASE_TYPE uxItemSize;        /*< The size of each items that the queue will hold. */
    15 
    16     volatile signed portBASE_TYPE xRxLock;    /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked.  Set to queueUNLOCKED when the queue is not locked. */
    17     volatile signed portBASE_TYPE xTxLock;    /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked.  Set to queueUNLOCKED when the queue is not locked. */
    18 
    19     #if ( configUSE_TRACE_FACILITY == 1 )
    20         unsigned char ucQueueNumber;
    21         unsigned char ucQueueType;
    22     #endif
    23 
    24 } xQUEUE;

    任务控制块中有两个列表成员,其中事件列表就是用于队列阻塞时用的。

    xGenericListItem是用于将任务串成列表的列表成员,后续该任务加入就绪任务列表还是其他任务列表,都是将该列表成员插入进任务列表。

    xEventListItem用于记录该任务是否在等待事件,比如是否向队列发送数据但队列已满、是否从队列读取数据但队列是空的,且设置了等待时间或无限等待。例如,若是向队列发送数据但队列已满,则该任务的xEventListItem会插入该队列的xTasksWaitingToSend列表中;同时将xGenericListItem从就绪任务列表删除,插入到挂起任务队列(若等待时间是无限)或延时任务队列(若等待时间是有限)(该过程由vTaskPlaceOnEventList完成)。若是队列非满了,则会将任务的xEventListItem从xTasksWaitingToSend中移除;同时,将任务的xGenericListItem从挂起任务队列或延时任务队列中移除,并添加到就绪队列中(该过程由xTaskRemoveFromEventList完成)。

     xQueueGenericSend和xQueueGenericSendFromISR的区别在与

    (1)如果队列已满,则,普通send会阻塞,而fromISR不会阻塞;

    (2)如果有任务因读取队列而阻塞且该任务优先级高,则普通send会马上yield,使能任务切换到高优先级任务,而fromISR则是返回一个标识。

      1 /*-----------------------------------------------------------*/
      2 
      3 signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
      4 {
      5 signed portBASE_TYPE xEntryTimeSet = pdFALSE;
      6 xTimeOutType xTimeOut;
      7 
      8     configASSERT( pxQueue );
      9     configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
     10 
     11     /* This function relaxes the coding standard somewhat to allow return
     12     statements within the function itself.  This is done in the interest
     13     of execution time efficiency. */
     14     for( ;; )
     15     {
     16         taskENTER_CRITICAL();
     17         {
     18             /* Is there room on the queue now?  To be running we must be
     19             the highest priority task wanting to access the queue. */
     20             if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
     21             {
     22                 traceQUEUE_SEND( pxQueue );
     23                 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
     24 
     25                 /* If there was a task waiting for data to arrive on the
     26                 queue then unblock it now. */
     27                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
     28                 {
     29                     if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )
     30                     {
     31                         /* The unblocked task has a priority higher than
     32                         our own so yield immediately.  Yes it is ok to do
     33                         this from within the critical section - the kernel
     34                         takes care of that. */
     35                         portYIELD_WITHIN_API();
     36                     }
     37                 }
     38 
     39                 taskEXIT_CRITICAL();
     40 
     41                 /* Return to the original privilege level before exiting the
     42                 function. */
     43                 return pdPASS;
     44             }
     45             else
     46             {
     47                 if( xTicksToWait == ( portTickType ) 0 )
     48                 {
     49                     /* The queue was full and no block time is specified (or
     50                     the block time has expired) so leave now. */
     51                     taskEXIT_CRITICAL();
     52 
     53                     /* Return to the original privilege level before exiting
     54                     the function. */
     55                     traceQUEUE_SEND_FAILED( pxQueue );
     56                     return errQUEUE_FULL;
     57                 }
     58                 else if( xEntryTimeSet == pdFALSE )
     59                 {
     60                     /* The queue was full and a block time was specified so
     61                     configure the timeout structure. */
     62                     vTaskSetTimeOutState( &xTimeOut );
     63                     xEntryTimeSet = pdTRUE;
     64                 }
     65             }
     66         }
     67         taskEXIT_CRITICAL();
     68 
     69         /* Interrupts and other tasks can send to and receive from the queue
     70         now the critical section has been exited. */
     71 
     72         vTaskSuspendAll();
     73         prvLockQueue( pxQueue );
     74 
     75         /* Update the timeout state to see if it has expired yet. */
     76         if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
     77         {
     78             if( prvIsQueueFull( pxQueue ) != pdFALSE )
     79             {
     80                 traceBLOCKING_ON_QUEUE_SEND( pxQueue );
     81                 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
     82 
     83                 /* Unlocking the queue means queue events can effect the
     84                 event list.  It is possible    that interrupts occurring now
     85                 remove this task from the event    list again - but as the
     86                 scheduler is suspended the task will go onto the pending
     87                 ready last instead of the actual ready list. */
     88                 prvUnlockQueue( pxQueue );
     89 
     90                 /* Resuming the scheduler will move tasks from the pending
     91                 ready list into the ready list - so it is feasible that this
     92                 task is already in a ready list before it yields - in which
     93                 case the yield will not cause a context switch unless there
     94                 is also a higher priority task in the pending ready list. */
     95                 if( xTaskResumeAll() == pdFALSE )
     96                 {
     97                     portYIELD_WITHIN_API();
     98                 }
     99             }
    100             else
    101             {
    102                 /* Try again. */
    103                 prvUnlockQueue( pxQueue );
    104                 ( void ) xTaskResumeAll();
    105             }
    106         }
    107         else
    108         {
    109             /* The timeout has expired. */
    110             prvUnlockQueue( pxQueue );
    111             ( void ) xTaskResumeAll();
    112 
    113             /* Return to the original privilege level before exiting the
    114             function. */
    115             traceQUEUE_SEND_FAILED( pxQueue );
    116             return errQUEUE_FULL;
    117         }
    118     }
    119 }
     1 /*-----------------------------------------------------------*/
     2 
     3 signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition )
     4 {
     5 signed portBASE_TYPE xReturn;
     6 unsigned portBASE_TYPE uxSavedInterruptStatus;
     7 
     8     configASSERT( pxQueue );
     9     configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
    10 
    11     /* Similar to xQueueGenericSend, except we don't block if there is no room
    12     in the queue.  Also we don't directly wake a task that was blocked on a
    13     queue read, instead we return a flag to say whether a context switch is
    14     required or not (i.e. has a task with a higher priority than us been woken
    15     by this    post). */
    16     uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
    17     {
    18         if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
    19         {
    20             traceQUEUE_SEND_FROM_ISR( pxQueue );
    21 
    22             prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
    23 
    24             /* If the queue is locked we do not alter the event list.  This will
    25             be done when the queue is unlocked later. */
    26             if( pxQueue->xTxLock == queueUNLOCKED )
    27             {
    28                 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
    29                 {
    30                     if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
    31                     {
    32                         /* The task waiting has a higher priority so record that a
    33                         context    switch is required. */
    34                         if( pxHigherPriorityTaskWoken != NULL )
    35                         {
    36                             *pxHigherPriorityTaskWoken = pdTRUE;
    37                         }
    38                     }
    39                 }
    40             }
    41             else
    42             {
    43                 /* Increment the lock count so the task that unlocks the queue
    44                 knows that data was posted while it was locked. */
    45                 ++( pxQueue->xTxLock );
    46             }
    47 
    48             xReturn = pdPASS;
    49         }
    50         else
    51         {
    52             traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );
    53             xReturn = errQUEUE_FULL;
    54         }
    55     }
    56     portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
    57 
    58     return xReturn;
    59 }

    大幅度发

  • 相关阅读:
    (转)使用Nios II 9.1 SP1 SBTE的Flash Programmer的几点注意事项
    [转]linux mysql 更改MySQL数据库目录位置
    2009年第二天被小偷光顾
    [转]几乎没人能逃过的定向思维,我做过了,几乎全对,最后想的是苹果、鼻子跟鸭子
    QQ群里一段推理(恶搞)
    [转]Visio虚线复制到word中变为实线问题的解决办法
    [转]Vmware中提供的与网络通讯的三种网络模式的讲解
    [转]Word 2007书籍排版完全手册
    好好造句
    地产忽悠大全
  • 原文地址:https://www.cnblogs.com/yanhc/p/12675967.html
Copyright © 2011-2022 走看看