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 )
信号量包括二值信号量、计数信号量、递归信号量、互斥信号量。
对于二值信号量,对存在优先级反转的问题。
比如任务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完成)。
大幅度发