FreeRTOS-队列优先级

多线程中的消息队列

互斥的引入

//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。

休眠唤醒线程

任务B 因为读不到数据而休眠 不抢占cpu资源
在这里插入图片描述

在线程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 函数等待一组事件中的某些事件。如果要等待特定事件,则可以将任务放到相应事件的事件列表中,直到事件发生。

系统Tick 中断不断在发生,Tick中断里判断delayed list 中的任务时间到了没有?时间到了就将其唤醒。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是加上注释的代码: #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 50 //最大数的个数 int num[MAX]; //输入的数 int flag[MAX]; //是否已经用过 int oper[MAX]; //1'+', 2'-', 3'*', 4'/' int n,m; int p[MAX];//临时数组 int bestp[MAX];//最优数组 int bestop[MAX];//最优操作符 char op[]={' ','+','-','*','/'}; //操作符数组 int k;//搜索深度逐渐加深 //判断是否满足条件 int found() { int result=p[1]; for(int i=1;i<=k;i++) //计算式子的结果 { switch(oper[i]) { case 1: result+=p[i+1]; break; case 2: result-=p[i+1]; break; case 3: result*=p[i+1]; break; case 4: result/=p[i+1]; break; } } return result==m; } //搜索所有可能的方案 int backtrack(int dep) { if(dep>k+1) //深度逐渐加深 { if(found()) { memcpy(bestp,p,sizeof(p)); memcpy(bestop,oper,sizeof(oper)); return 1; } else return 0; } for(int j=1;j<=n;j++) //可选的数字 { if(flag[j]>0) continue; p[dep]=num[j]; flag[j]=1; for(int i=1;i<=4;i++) //可选的操作符 { oper[dep]=i; if(backtrack(dep+1)) return 1; oper[dep]=0; } flag[j]=0; p[dep]=0; } return 0; } int main() { printf("输入整数个数:"); scanf("%d",&n); printf("%d\n",n); printf("输入目标数:"); scanf( "%d",&m); printf("%d\n",m); printf("输入各整数:\n"); for(int i=1;i<=n;i++) { scanf("%d",&num[i]); } for(k=0;k<n;k++) { if(backtrack(0)) { printf("\n最少无优先级运算次数为:%d\n",k); printf("最优无优先级运算表达式为:\n"); for(int i=1;i<=k;i++) printf("%d%c",bestp[i],op[bestop[i]]); printf("%d\n",bestp[k+1]); break; } } return 0; }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值