//C语言
int a ;
main(){
fun_a ();
fun_b();
}
// RTOS
int a;
main(){
createtask(A_fun);
createtask(B_fun);
}
RTOS为 同时运行
A_fun 和 B_fun 中的 a++
- 读a :R0 = [a]
- 修改:R0 = R0 +1
- 写a :R0 = [a]
但线程B 会将线程A 的断点提取出来 出现结果a 两个线程运行后 a值不为2 为1
queueSend{ 1.关闭中断 2.写数据 3.开中断}
QueueSend是一个线程同步的互斥函数,用于将数据发送到消息队列中,并阻塞线程直到数据传送成功。
该函数的内容如下:
BaseType_t QueueSend( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait );
其中,参数含义如下:
xQueue
: 指向要发送数据的目标消息队列的句柄。pvItemToQueue
: 指向要发送的数据的指针。xTicksToWait
: 阻塞线程的最长时间,以FreeRTOS时钟依赖的tick为单位。该函数会提取一个空闲的消息队列条目,将要发送的数据按照先进先出的顺序添加到该条目中,并将条目放入目标队列。当消息队列已满时,队列的发送函数将阻塞线程,直到有空闲条目可用,或等待时间超时(如果已指定等待时间)。
如果成功将数据发送到目标队列,则返回pdPASS。否则,返回pdFAIL。
在线程A中写队列后,对线程B进行唤醒
线程B 读数据后 无数据(data)后进行休眠 将自身从就绪链表(ready.list)移动到 delay链表(delay.list) 再将自己记录在队列链表中(queue.list) 中
BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition )
{
TCB_t * pxTask;
BaseType_t xEntryTimeSet = pdFALSE;
const TickType_t xTickCount = xTaskGetTickCount();
BaseType_t xYieldRequired = pdFALSE;
const List_t *pxConstQueue = ( const List_t * ) xQueue;
Queue_t * const pxQueue = ( Queue_t * ) pxConstQueue;
if( xQueue == NULL )
{
return errQUEUE_NULL;
}
else if( pxQueue->uxItemSize != ( UBaseType_t ) 0U )
{
configASSERT( pvItemToQueue );
traceQUEUE_SEND( xQueue );
vTaskSuspendAll();
{
if( uxQueueSpacesAvailable( pxQueue ) != ( UBaseType_t ) 0U )
{
/* There is space in the queue. Is memory being copied or
dynamically allocated? */
const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;
/*仅当调用 memcpy() 时,这在函数中设置为 true(在这种情况下,不能有任务等待) */
pxQueue->xTxLock = pdFALSE;
if( xCopyPosition == queueSEND_TO_BACK )
{
prvCopyDataToQueue( pxQueue->pcTail, pvItemToQueue, pxQueue->uxItemSize );
pxQueue->pcTail += pxQueue->uxItemSize;
if( pxQueue->pcTail == pxQueue->pcTailEnd )
{
pxQueue->pcTail = pxQueue->pcHead;
}
}
else if( xCopyPosition == queueSEND_TO_FRONT )
{
if( pxQueue->pcHead == pxQueue->pcQueueStorage )
{
pxQueue->pcHead = pxQueue->pcTailEnd - pxQueue->uxItemSize;
}
else
{
pxQueue->pcHead -= pxQueue->uxItemSize;
}
prvCopyDataToQueue( pxQueue->pcHead, pvItemToQueue, pxQueue->uxItemSize );
}
else if( xCopyPosition == queueOVERWRITE )
{
if( ( uxMessagesWaiting ) != ( pxQueue->uxLength ) )
{
/* There is space in the queue. Is memory being copied or
dynamically allocated? */
if( ( uint8_t * ) pvItemToQueue == pxQueue->pcWriteTo )
{
/* Avoid a copy, by moving the write pointer past the
value that is being overwritten. */
pxQueue->pcWriteTo += pxQueue->uxItemSize;
if( pxQueue->pcWriteTo == pxQueue->pcTailEnd )
{
pxQueue->pcWriteTo = pxQueue->pcQueueStorage;
}
}
else
{
prvCopyDataToQueue( pxQueue->pcWriteTo, pvItemToQueue, pxQueue->uxItemSize );
pxQueue->pcWriteTo += pxQueue->uxItemSize;
if( pxQueue->pcWriteTo == pxQueue->pcTailEnd )
{
pxQueue->pcWriteTo = pxQueue->pcQueueStorage;
}
}
}
else
{
/* The queue is full and we are to overwrite the data.
We can only do that if the task attempting the write is
the one at the head of the queue. */
if( ( &xTaskGetCurrentTaskHandle() )->pxTaskTag ==
( void * ) pxQueue->pxTasksWaitingToReceive->pxTasks[ pxQueue->uxLength - ( UBaseType_t ) 1U ] )
{
const uint8_t *pcOriginalReadPosition = pxQueue->pcReadFrom;
/* Discard the oldest data in the queue to make way
for the new. */
if( pxQueue->pcReadFrom == pxQueue->pcTailEnd )
{
pxQueue->pcReadFrom = pxQueue->pcQueueStorage;
}
pxQueue->pcReadFrom += pxQueue->uxItemSize;
if( pxQueue->pcReadFrom == pxQueue->pcTailEnd )
{
pxQueue->pcReadFrom = pxQueue->pcQueueStorage;
}
/* Insert the new data at the free end of the queue. */
prvCopyDataToQueue( pxQueue->pcWriteTo, pvItemToQueue, pxQueue->uxItemSize );
pxQueue->pcWriteTo += pxQueue->uxItemSize;
if( pxQueue->pcWriteTo == pxQueue->pcTailEnd )
{
pxQueue->pcWriteTo = pxQueue->pcQueue
唤醒queue 队列任务中 把queue.xTasksWaitingTosend 中第一个任务移除
把它从Delay.list[ ] 中移动到 ready.list[ ] 中
FreeRTOS中的xQueueReceive函数用于从队列中接收一项数据,它的代码如下:
BaseType_t xQueueReceive( QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait )
{
Queue_t * const pxQueue = xQueue;
BaseType_t xEntryTimeSet = pdFALSE, xYieldRequired;
const TickType_t xBlockTime = xTicksToWait;
configASSERT( pxQueue );
configASSERT( pvBuffer );
vTaskSuspendAll();
{
if( prvIsQueueEmpty( pxQueue ) )
{
if( xBlockTime != ( TickType_t ) 0 )
{
if( xTaskCheckForTimeOut( &pxQueue->xTasksWaitingToReceive, &xBlockTime ) == pdFALSE )
{
if( pxQueue->xRxLock == pdFALSE )
{
if( pxQueue->xTasksWaitingToSend.cListLength > (UBaseType_t) 0 )
{
/* Unblock the task that was blocked waiting to send to the
queue. */
( void ) xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) );
prvAddTaskToReadyQueue( pxQueue->xTasksWaitingToSend.pxHead, pxTaskGetSchedulerState() );
if( pxQueue->xTasksWaitingToSend.xTaskListItem.xItemValue < pxCurrentTCB->uxPriority )
{
xYieldRequired = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
xYieldRequired = pdFALSE;
}
}
else
{
pxQueue->xTasksWaitingToReceive.cListLength++;
vTaskPlaceOnUnorderedEventList( &( pxQueue->xTasksWaitingToReceive ), xBlockTime );
pxQueue->xRxLock = pdTRUE;
xYieldRequired = prvLockQueue( &( pxQueue->xTasksWaitingToReceive ) );
}
}
else
{
xYieldRequired = prvLockQueue( &( pxQueue->xTasksWaitingToReceive ) );
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
/* There was data in the queue. */
mtCOVERAGE_TEST_MARKER();
if( pxQueue->xRxLock == pdFALSE )
{
prvCopyDataFromQueue( pxQueue, pvBuffer );
xYieldRequired = prvLockQueue( &( pxQueue->xTasksWaitingToSend ) );
}
else
{
xYieldRequired = prvLockQueue( &( pxQueue->xTasksWaitingToSend ) );
prvCopyDataFromQueue( pxQueue, pvBuffer );
}
}
}
xTaskResumeAll();
if( xYieldRequired != pdFALSE )
{
taskYIELD(); //任务退让
}
return xYieldRequired;
}
这段代码主要是在对队列进行操作,首先通过传入的队列句柄xQueue得到pxQueue,然后挂起所有任务。如果队列为空,xQueueReceive函数会优先判断是否有任务在等待发送数据。如果有,则会将等待发送的任务从队列xTasksWaitingToSend中移除,并加入到任务就绪队列中。如果没有,则将当前任务加入到等待接收数据的队列xTasksWaitingToReceive中,并设置pxQueue->xRxLock为pdTRUE,表示队列已经有一个任务在接收数据了。如果队列不为空,则根据pxQueue->xRxLock的值来确定如何处理,如果为pdFALSE,则直接从队列中读取数据,否则先将数据读取出来,再将当前任务加入到等待发送数据的队列xTasksWaitingToSend中。然后释放挂起的任务并返回是否需要进行任务切换的标志xYieldRequired。
- 这里的 prvLockQueue函数是FreeRTOS内部实现的函数,主要作用是释放xQueueReceive函数中的挂起任务并返回是否需要任务切换的标志。
- 其中的 pxTaskGetSchedulerState() 函数是 FreeRTOS 操作系统中的一个 API 函数,用于获取调度器的当前状态。该函数返回一个枚举值,可以用于确定当前调度器的状态是运行或停止。它还可以用于确定调度器是否已经初始化。通过调用此函数,可以帮助程序员更好地了解操作系统的状态,从而更好地调试和控制系统行为。
- vTaskSuspendAll是一个FreeRTOS API函数,用于暂停调度器中的所有任务(除了在调用vTaskSuspendAll之前已经处于阻塞状态的任务),并禁止调度器从处于挂起状态的任何任务处进行上下文切换。这是实现临界区和互斥操作的一种方式。在调用vTaskSuspendAll之后,任务可以安全地访问共享资源或执行其他需要原子性的操作,而不必担心任务间的竞争和冲突问题。在完成需要保护的操作后,可以使用xTaskResumeAll函数来恢复调度器的正常运行。
- vTaskPlaceOnUnorderedEventList 函数是 FreeRTOS 操作系统中用来将任务放置在无序事件列表中的函数。该函数将任务对象放置到指定的事件列表中,而不进行排序。这意味着任务在事件列表中的位置可能是任意的,而不是按优先级排列的。这个函数通常与事件标志一起使用,用于等待特定事件发生。任务可以使用 xEventGroupWaitBits 函数等待一组事件中的某些事件。如果要等待特定事件,则可以将任务放到相应事件的事件列表中,直到事件发生。