07_FreeRTOS任务调度器的挂起和恢复

news2024/9/24 13:19:43

任务调度器的挂起和恢复

挂起任务调度器,调用此函数不需要关闭中断

 

 使用格式示例:

 1.与临界区不一样的是,挂起任务调度器,未关闭中断;

2.它仅仅是防止;饿任务之间的资源争夺,中断照样可以直接响应;

3.挂起调度器的方式,适合于临界区位于任务与任务之间;既不用去延时中断,又可以做临界区的安全。

vTaskSuspendAll()任务调度器挂起函数详解

void vTaskSuspendAll( void )
{
	/* A critical section is not required as the variable is of type
	BaseType_t.  Please read Richard Barry's reply in the following link to a
	post in the FreeRTOS support forum before reporting this as a bug! -
	http://goo.gl/wu4acr */
	
	/*对变量加1,其实任务调度就是任务切换,任务切换又PendSV中断实现中断,进行任务切换*/
	++uxSchedulerSuspended;
}

PendSV的触发是在SysTick定时器中断里面触发的, xPortSysTickHandler()。

void SysTick_Handler(void)
{	
    if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
    {
        xPortSysTickHandler();	
    }
}
void xPortSysTickHandler( void )
{
	/* The SysTick runs at the lowest interrupt priority, so when this interrupt
	executes all interrupts must be unmasked.  There is therefore no need to
	save and then restore the interrupt mask value as its value is already
	known - therefore the slightly faster vPortRaiseBASEPRI() function is used
	in place of portSET_INTERRUPT_MASK_FROM_ISR(). */
	
	/*将BASEPRI设置为最大系统调用优先级,以实现临界区*/
	vPortRaiseBASEPRI();
	{
		/* Increment the RTOS tick. */
		/*返回的是pdFALSE所以不会触发PendSV中断不会任务切换,认为是调度器挂起了*/
		if( xTaskIncrementTick() != pdFALSE )
		{
			/* A context switch is required.  Context switching is performed in
			the PendSV interrupt.  Pend the PendSV interrupt. */
			/*触发PendSV中断*/
			portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
		}
	}
	vPortClearBASEPRIFromISR();
}
BaseType_t xTaskIncrementTick( void )
{
TCB_t * pxTCB;
TickType_t xItemValue;
BaseType_t xSwitchRequired = pdFALSE;

	/* Called by the portable layer each time a tick interrupt occurs.
	Increments the tick then checks to see if the new tick value will cause any
	tasks to be unblocked. */
	/*为实现*/
	traceTASK_INCREMENT_TICK( xTickCount );
	/*判断变量,此变量在调用挂起任务调度器时会加1,所以不回进入到if里面*/
	if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
	{
		/* Minor optimisation.  The tick count cannot change in this
		block. */
		const TickType_t xConstTickCount = xTickCount + 1;

		/* Increment the RTOS tick, switching the delayed and overflowed
		delayed lists if it wraps to 0. */
		xTickCount = xConstTickCount;

		if( xConstTickCount == ( TickType_t ) 0U )
		{
			taskSWITCH_DELAYED_LISTS();
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}

		/* See if this tick has made a timeout expire.  Tasks are stored in
		the	queue in the order of their wake time - meaning once one task
		has been found whose block time has not expired there is no need to
		look any further down the list. */
		if( xConstTickCount >= xNextTaskUnblockTime )
		{
			for( ;; )
			{
				if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
				{
					/* The delayed list is empty.  Set xNextTaskUnblockTime
					to the maximum possible value so it is extremely
					unlikely that the
					if( xTickCount >= xNextTaskUnblockTime ) test will pass
					next time through. */
					xNextTaskUnblockTime = portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
					break;
				}
				else
				{
					/* The delayed list is not empty, get the value of the
					item at the head of the delayed list.  This is the time
					at which the task at the head of the delayed list must
					be removed from the Blocked state. */
					pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
					xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );

					if( xConstTickCount < xItemValue )
					{
						/* It is not time to unblock this item yet, but the
						item value is the time at which the task at the head
						of the blocked list must be removed from the Blocked
						state -	so record the item value in
						xNextTaskUnblockTime. */
						xNextTaskUnblockTime = xItemValue;
						break;
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}

					/* It is time to remove the item from the Blocked state. */
					( void ) uxListRemove( &( pxTCB->xStateListItem ) );

					/* Is the task waiting on an event also?  If so remove
					it from the event list. */
					if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
					{
						( void ) uxListRemove( &( pxTCB->xEventListItem ) );
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}

					/* Place the unblocked task into the appropriate ready
					list. */
					prvAddTaskToReadyList( pxTCB );

					/* A task being unblocked cannot cause an immediate
					context switch if preemption is turned off. */
					#if (  configUSE_PREEMPTION == 1 )
					{
						/* Preemption is on, but a context switch should
						only be performed if the unblocked task has a
						priority that is equal to or higher than the
						currently executing task. */
						if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
						{
							xSwitchRequired = pdTRUE;
						}
						else
						{
							mtCOVERAGE_TEST_MARKER();
						}
					}
					#endif /* configUSE_PREEMPTION */
				}
			}
		}

		/* Tasks of equal priority to the currently running task will share
		processing time (time slice) if preemption is on, and the application
		writer has not explicitly turned time slicing off. */
		#if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
		{
			if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 )
			{
				xSwitchRequired = pdTRUE;
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */

		#if ( configUSE_TICK_HOOK == 1 )
		{
			/* Guard against the tick hook being called when the pended tick
			count is being unwound (when the scheduler is being unlocked). */
			if( uxPendedTicks == ( UBaseType_t ) 0U )
			{
				vApplicationTickHook();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		#endif /* configUSE_TICK_HOOK */
	}
	/*挂起任务调度器进入此处*/
	else
	{
		
		++uxPendedTicks;

		/* The tick hook gets called at regular intervals, even if the
		scheduler is locked. */
		#if ( configUSE_TICK_HOOK == 1 )
		{
			vApplicationTickHook();
		}
		#endif
	}

	#if ( configUSE_PREEMPTION == 1 )
	{
		if( xYieldPending != pdFALSE )
		{
			xSwitchRequired = pdTRUE;
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	#endif /* configUSE_PREEMPTION */
	
	/*返回0*/
	return xSwitchRequired;
}

总结:

vTaskSuspendAll(),调用一次挂起调度器,该变量uxSchedulerSuspended就加一,变量uxSchedulerSuspended的值不为0,将会导致Systick无法触发PendSV中断,即挂起调度器

xTaskResumeAll()任务调度器挂起函数详解

BaseType_t xTaskResumeAll( void )
{
TCB_t *pxTCB = NULL;
BaseType_t xAlreadyYielded = pdFALSE;

	/* If uxSchedulerSuspended is zero then this function does not match a
	previous call to vTaskSuspendAll(). */
	configASSERT( uxSchedulerSuspended );

	/* It is possible that an ISR caused a task to be removed from an event
	list while the scheduler was suspended.  If this was the case then the
	removed task will have been added to the xPendingReadyList.  Once the
	scheduler has been resumed it is safe to move all the pending ready
	tasks from this list into their appropriate ready list. */
	/*进入临界区*/
	taskENTER_CRITICAL();
	{	
		/*变量减1,挂起是把此变量加1,恢复是把这个变量减1*/
		--uxSchedulerSuspended;
		/*如果这个变量等于pdFALSE(0)的时候,代表调度器恢复了*/
		if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
		{	
			/*判断创建任务的总数是不是大于0*/
			if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U )
			{
				/* Move any readied tasks from the pending list into the
				appropriate ready list. */
				/*判断等待就绪列表是否有任务,有的话执行while*/
				while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
				{
					/*把所在的所有列表移除*/
					pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );
					( void ) uxListRemove( &( pxTCB->xEventListItem ) );
					( void ) uxListRemove( &( pxTCB->xStateListItem ) );
					/*添加到就绪列表里*/
					prvAddTaskToReadyList( pxTCB );

					/* If the moved task has a priority higher than the current
					task then a yield must be performed. */
					/*判断恢复的任务优先级是否大于当前的任务*/
					if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
					{
						/*执行任务切换*/
						xYieldPending = pdTRUE;
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}

				if( pxTCB != NULL )
				{
					/* A task was unblocked while the scheduler was suspended,
					which may have prevented the next unblock time from being
					re-calculated, in which case re-calculate it now.  Mainly
					important for low power tickless implementations, where
					this can prevent an unnecessary exit from low power
					state. */
					/*更新下次阻塞时间*/
					prvResetNextTaskUnblockTime();
				}

				/* If any ticks occurred while the scheduler was suspended then
				they should be processed now.  This ensures the tick count does
				not	slip, and that any delayed tasks are resumed at the correct
				time. */
				{
					/*恢复滴答定时器,被挂起时丢失的任务数*/
					UBaseType_t uxPendedCounts = uxPendedTicks; /* Non-volatile copy. */

					if( uxPendedCounts > ( UBaseType_t ) 0U )
					{
						do
						{
							if( xTaskIncrementTick() != pdFALSE )
							{
								xYieldPending = pdTRUE;
							}
							else
							{
								mtCOVERAGE_TEST_MARKER();
							}
							/*补齐一次减一直,知道全部补齐*/
							--uxPendedCounts;
						} while( uxPendedCounts > ( UBaseType_t ) 0U );

						uxPendedTicks = 0;
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}
				/*xYieldPending不等于pdFALSE代表需要任务切换*/
				if( xYieldPending != pdFALSE )
				{
					/*不等于0代表使用抢占式调度*/
					#if( configUSE_PREEMPTION != 0 )
					{
						/*变量赋值*/
						xAlreadyYielded = pdTRUE;
					}
					#endif
					/*执行任务切换*/
					taskYIELD_IF_USING_PREEMPTION();
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	/*退出临界区*/
	taskEXIT_CRITICAL();

	return xAlreadyYielded;
}

总结:

xTaskResumeAll(),调用一次恢复调度器,该变量uxSchedulerSuspended就减一,如果等于0,则允许调度:

1. 当任务数量大于0时,恢复调度器才有意义,如果没有一个已创建的任务就无意义

2.移除等待就绪列表中的列表项,恢复至就绪列表,直到xPendingReadyList列表为空

3.如果恢复的任务优先级比当前正在执行任务优先级更高,则将xYieldPending赋值为pdTRUE,表示需要进行一次任务切换

4.在调度器被挂起的期间内,是否有丢失未处理的滴答数。 xPendedCounts是丢失的滴答数,有则调用xTasklncrementTickf )补齐弄失的滴答数

5.判断是否允许任务切换

6.返回任务是否已经切换;已经切换返回pdTRUE;反之返回pdFALSE

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/176334.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL 8.0.31 集合操作INTERSECT和EXCEPT

对于聚合的功能MySQL是都是默默的发展。在最新的8.0.31版本中提供对集合操作INTERSECT和EXCEPT。这样一来&#xff0c;集合操作功能基本圆满了。MySQL5.7.40版本是不支持这个集合的。 In this release MySQL adds support for the SQL standard INTERSECT and EXCEPT table op…

Linux常用命令——ssh命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) ssh openssh套件中的客户端连接工具 补充说明 ssh命令是openssh套件中的客户端连接工具&#xff0c;可以给予ssh加密协议实现安全的远程登录服务器。 语法 ssh(选项)(参数)选项 -1&#xff1a;强制使用ssh协…

基于FPGA的时间数字转换(TDC)设计(四)

1. 基于IODELAY的TDC设计原理 在第一篇中讲过,基于FPGA开发的TDC常见的有直接计数法,多相位时钟采样法,抽头延迟线法等等。前面3篇讲解了基于多相位的TDC,接下来主要讲解基于抽头延迟线的方法。在Xilinx FPGA开发中,要实现抽头延迟线,主要由进位链(Carry4)和IODELAY模块…

寒假题练——day(6)

题目1&#xff1a; 有一种兔子&#xff0c;从出生后第3个月起每个月都生一只兔子&#xff0c; 小兔子长到第三个月后每个月又生一只兔子。 例子&#xff1a;假设一只兔子第3个月出生&#xff0c;那么它第5个月开始会每个月生一只兔子。 一月的时候有一只兔子&#xff0c;假如兔…

检索方案优化

文章目录 1. Flab框架概览2. Flab框架各个层在基金检索的具体应用2.1. 前置检查Check层2.2. 多路召回Recall层2.3. 结果集过滤2.3.1. 问财和我们召回结果的交集2.4. 排序Rank2.5. 缓存Cache2.6. 封装Assmeble1. Flab框架概览 Fly like a bird 寓意灵活 2. Flab框架各个层在基金…

2023年大年初一 —— 牛客网刷题经验分享~

2023年大年初一 —— 牛客网刷题经验分享~&#x1f60e;大年初一 —— 牛客网刷题经验分享~&#x1f60e;)前言&#x1f64c;BC94 反向输出一个四位数 &#x1f60a;BC95 小乐乐与进制转换 &#x1f60a;BC96 [NOIP2015]金币&#x1f60a;BC97 回文对称数 &#x1f60a;总结撒花…

pytorch 神经网络基础入门笔记【b站小土堆】

文章目录python深度学习配置环境anacondapycharmpytorchpython学习中的两大法宝函数加载数据Tensorboard使用torchvision中的transformstensor数据类型transform该如何使用为什么我们需要Tensor类型更好的使用transformsToTensorNormalizeResizeComposeRandomCrop总结torchvisi…

JVM快速入门学习笔记(三)

9. 栈 栈&#xff1a;8大基本类型对象引用 栈运行原理&#xff1a;栈帧 程序正在执行的方法&#xff0c;一定在栈的顶部 9.1 JVM数据区 先上一张Java虚拟机运行时数据区中堆、栈以及方法区存储数据的概要图&#xff0c;如下所示&#xff1a; 9.2 堆 堆是存储时的单位&…

美团出品 | YOLOv6 v3.0 is Coming(超越YOLOv7、v8)

&#x1f680;&#x1f680;&#x1f680;美团出品 | YOLOv6 v3.0 is Coming &#xff01;&#xff01;✨✨✨ 一、前言简介 &#x1f384;&#x1f388; &#x1f4da; 代码地址&#xff1a;美团出品 | YOLOv6 3.0代码下载地址 &#x1f4da; 文章地址&#xff1a;https://a…

四、python-pyecharts图表可视化(黑马程序猿-python学习记录)

黑马程序猿的python学习视频&#xff1a;https://www.bilibili.com/video/BV1qW4y1a7fU/ 目录 1. 官网链接 2. 下载pyecharts 3. 编写一个折线图 4. 隐藏线段上的数据 5. 绘制柱状图 6. 柱状图的xy轴反转 7. 柱状图设置提示在最右边 8. 时间柱状图 9. 时间柱状图设置颜色主题 …

第三章 AOP

1.AOP基本概念*什么是AOP&#xff1a;面向切面编程&#xff0c;利用AOP可以对业务逻辑的各个部分进行隔离&#xff0c;从而使得业务逻辑各个部分之间的耦合度降低&#xff0c;提高程序的可重用性&#xff0c;同时提高开发效率&#xff08;不通过修改源代码方式&#xff0c;在主…

深入跨域问题(2) - 利用 CORS 解决跨域

目录 1.搭建跨域环境(先展示一下跨域请求的情况)&#xff1a; 2.处理非预请求 3.处理 POST 预请求 4.总结&#xff1a; 1.搭建跨域环境(先展示一下跨域请求的情况)&#xff1a; 模拟客户端请求&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <…

客快物流大数据项目(一百零七):物流信息查询服务接口开发解决方案

文章目录 物流信息查询服务接口开发解决方案 一、业务需求

探究数据库mysql的vachar、test、longtext存储极限

文章目录背景介绍项目实操如果想要自己尝试&#xff0c;使用Apipost工具&#xff0c;调用接口测试即可mysql类型如果感觉有点意思点个关注&#xff0c;一键三连吧&#xff01;蟹蟹&#xff01;&#xff01;&#xff01;背景 想要清晰的了解到&#xff0c;使用longtext类型&…

C++:类的构造函数与析构函数

目录 一.前言 二.类的构造函数 1.构造函数基本概念与语法细则 2.编译器默认生成的无参构造函数和自定义构造函数 3.构造函数的特性(可重载) 4.关于构造函数的注意事项 5.构造函数的应用示例&#xff1a; 三.类的拷贝构造函数 1.拷贝构造函数基本概念 2.编译器默认生成…

零入门容器云实战之文章目录列表

建议: 1、网盘资源 零入门容器云网络实战 链接: https://pan.baidu.com/s/1nPLRkAwjItAHmtEU2T1F4g 提取码: rrpd 2、技术交流群 QQ群&#xff1a; 342498897 3、发布说明 绿色字体&#xff0c; 表示已经发布&#xff0c;可以观看 灰色字体&#xff0c; 表示未发布 发布频…

汽车研究(科普)

什么是汽车的排量&#xff0c;1.5L与2.0T又是指什么? 汽车的动力来源于燃油在气缸内爆燃产生的力&#xff0c;力推动活塞连着曲轴传到离合变速箱&#xff0c;通过后桥作用让车轮转&#xff0c;排量1.5、2.0指的就是气缸的容量&#xff0c;如果是带增压的用字母T表示&#xff0…

JQuery总结(二)

属性操作&#xff1a; 文本操作&#xff1a; <div><span>内容</span></div><input type"text" value"请输入内容"> </body> <script src"jQuery.min.js"></script> <script > console.lo…

目录 行盒的盒模型 显著特点 行块盒 空白折叠 可替换元素 和 非可替换元素 分页例子 display:inline-block object-fit

目录行盒的盒模型行盒显著特点行块盒空白折叠可替换元素 和 非可替换元素行盒的盒模型 常见的行盒&#xff1a;包含具体内容的元素 span、strong、em、i、img、video、audio 这些行盒模型也都有 content、padding、border、margin的 但它们与块盒还是有明显区别 行盒显著特…