最新文�? 原创 : ubuntu16.04怎样才能安装 wxpython 2.8.12.1 转载 : gerrit安装与配置 原创 : RobotFramework框架系列 – 介绍篇 原创 : RobotFramework框架系列 – 运行参数篇 原创 : RobotFramework框架系列 – TAG选择运行篇
原创 : FreeRTOS --(7)任务管理之入门篇 历史版本:
上次修改时间:

引用自

原创 : FreeRTOS --(7)任务管理之入门篇

FreeRTOS --(7)任务管理之入门篇

目录

1、任务状态

2、任务创建

3、任务优先级

4、任务阻塞

5、任务挂起

6、空闲任务

5、任务调度

5.1、抢占式调度

5.2、协作式调度


 

任务管理是操作系统中重中之重,不管什么 OS ,任务的调度管理都是核心,FreeRTOS 也是一样;在深入到 FreeRTOS 任务管理的源码之前,鄙人觉得有必要先去从全局的角度进行把握,从全局到局部,从粗线条,到细节,鄙人觉得这样方可更快的熟悉相关的内部原理;

从全局来看的话,可以先梳理 FreeRTOS 关于任务相关的 APIs,支持的 Feature,以及相关的特性,这样一来,在深入到源码级分析的话,知道使用场景,便知道为何这样设计;

分析基于 FreeRTOS V 10.3.1

首先,FreeRTOS 任务支持如下特性:

1、多任务执行; 2、支持配置任务优先级; 3、支持任务的阻塞,挂起; 4、任务都是自己的栈空间; 5、支持周期性任务; 6、任务抢占; 7、协作式调度;

 

1、任务状态

在单核处理器上,多任务是宏观并行,微观串行的;每个任务可以处于不同的状态:

几乎所有的 OS 下,任务都分为了 Ready、Blocked、Running、Suspend 等状态;这样划分是根据具体的使用场景进行的;

Running:指的是正在运行的任务,在单核系统中,同一时刻只有一个任务处于 Running; Ready:指的是可以被调度运行的任务,也就是处于就绪的任务; Blocked:指的是因为某种原因(等待资源,等待时间)暂时不满足执行条件的任务的状态; Suspend:指的是被挂起的任务,暂时不参与调度的状态;

 

2、任务创建

FreeRTOS 中,创建一个任务使用 **xTaskCreate **接口:

BaseType_t xTaskCreate(  TaskFunction_t pvTaskCode,
                         const char * const pcName,
                         unsigned short usStackDepth,
                         void *pvParameters,
                         UBaseType_t uxPriority,
                         TaskHandle_t * pvCreatedTask);

参数的含义如下:

pvTaskCode:任务执行的函数,此函数必须是一个死循环,不会返回。 pcName:任务的名字,是一个字符串;最大长度由宏 configMAX_TASK_NAME_LEN 指定,该宏位于 FreeRTOSConfig.h 文件中。 usStackDepth:任务堆栈的大小,它的单位不是字节,比如在 32-bits 位宽的情况下,这个值设置为 100,那么就是分配了 400 字节大小的堆栈。 pvParameters:传递给任务执行函数的参数。 uxPriority:任务的优先级。 pvCreatedTask:创建任务成功后的任务句柄,后期可以使用这个句柄来调用任务相关的 API。

返回值的含义如下:

Return:如果创建任务成功,返回 pdPASS 否则返回 pdFAIL

比如:

创建了两个任务 vTask1 和 vTask2,堆栈深度为 1000,优先级都为 1,没有入参;

创建完后,两个任务都默认被添加进入了 Ready 状态,调用 vTaskStartScheduler() 开启调度器;

它们的实现都是无限循环,执行的时候,进行打印;

它们在时间线上的执行如图所示:

 

3、任务优先级

在任务初始化的时候,可以指定任务的优先级,同样在任务运行过程中,也可以通过 API 来改变任务的优先级;

FreeRTOS 支持的最大优先级由 configMAX_PRIORITIES 确定,优先级的值越低,代表优先级越低;0 是最低优先级,所有在 FreeRTOS 中,优先级的范围处于 0 ~ configMAX_PRIORITIES 之间;

因为任务存在优先级不一样,调度器总是选择处于 Ready 状态的优先级最高的任务;

比如:

Task 1 优先级是 1,Task 2 优先级是 2;两个 Task 都是之前的实现的情况下,每次调度器选择任务的时候,因为 Task 2 优先级高,每次都会选择 Task 2,那么 Task 1 就会被饿死:

 

4、任务阻塞

类似上面的情况,Task 1 被饿死,得不到执行,显然不是我们想要的,归根结底,是因为 Task 2 一直满足执行条件!按照设计来说,Task 2 优先级高,它应该是去做一些急需快速完成的任务,其他任何事情不准阻拦他,但是哪有任务一直都急需被完成呢?所以,正常情况下,Task 2 可能是在等待某个事件(比如,某个中断后)或者某个时间点来完成急需完成的任务,其他时间应该处于一种等待的状态,我们称之为阻塞,也就是 Blocked;

在 FreeRTOS 中,有两种方式可以让任务进入阻塞状态:

1、阻塞在时间上:也就是执行任务的时间未到; 2、等待事件:也就是对应的事件还没有发生;

如果类似上面的代码,在死循环里面调用了 vTaskDelay 函数,这就是会导致任务处于阻塞状态,等时间到了指定的延时后,才再次进入 Ready 状态,被调度器调度;

在这种设计下,不同优先级的任务同时运行的时候,就不会有被饿死的情况,同时当两个任务都没有执行的时候,时间让给 IDLE 线程:

5、任务挂起

被挂起的任务,进入 Suspend 状态,调度器在任务选择的时候,不再调度进入 Suspend 状态的任务,除非再次对此任务调用 Resume,重新进入 Ready 队列,接受调度器的调度;

 

6、空闲任务

在调度器初始化的时候,会创建一个 Idle 任务,这样可以确保至少有一个任务在运行;此任务优先级最低,为 0;

空闲任务用来在处理被删除的任务的内存,所有删除任务后,一定要确保空闲任务被运行,这样才能够内存回收;

FreeRTOS 支持空闲任务的钩子函数,当开启 configUSE_IDLE_HOOK 宏是 1 的时候,在空闲任务的时候,函数:

void vApplicationIdleHook( void );

被调用,常用的方式是在此实现低功耗相关的处理逻辑;

 

5、任务调度

5.1、抢占式调度

FreeRTOS 的任务调度基于周期性的 Tick 心跳,调度器从 Ready 状态列表中选择下一个优先级最高的任务投入运行;被阻塞的任务可以通过 event 来临或者阻塞时间到,重新进入 Ready 状态;

软件上,可以通过配置宏,来改变调度算法的行为,这些宏位于 FreeRTOSConfig.h

configUSE_PREEMPTION:配置为 1 则说明支持抢占式调度,否则称之为协作式调度;

注:协作式调度需要任务主动放弃 CPU,下一个才能够被调度;抢占式调度由系统决定调度;

**configUSE_TIME_SLICING **:配置为 1 的时候,同样优先级的任务会被轮转调度执行;否则优先级相同的任务,不会被轮转执行,只会执行其中一个;

最常用的配置是,上述两个都配置为 1;

configUSE_PREEMPTION = 1 configUSE_TIME_SLICING = 1

比如有 3 个任务:Task 1、Task 2、Task 3 如下所示,他们的优先级也标记出来;

Task 1 处于 blocked 状态,等待 event 满足条件; Task 2 是周期性任务; Task 3 是低优先级任务,也处于 blocked 状态,等待它的 event; t1 时刻,Task 2 执行,Task 1 和 Task 3 的 event 都没满足; t2 时刻,没有任务执行,Idle 线程执行; t3 时刻,Task 3 的 event 满足了,被调度执行; t4 时刻,执行 Idle; t5 时刻,Task 3 的 event 满足了,被调度执行; t6 时刻,Task 2 周期性任务来了,优先级高于 Task 3,即便是 Task 3 未执行完,OS 依然调度 Task 2 先执行; t7 时刻,Task 2 执行完毕,OS 调度 Task 3; t8 时刻,没有需要调度的任务,进入 Idle; t9 时刻,Task 2 周期性任务来了,被调度; t10时刻,最高优先级的 Task 1 的 event 满足,即便是 Task 2 未执行完,OS 依然调度 Task 1 执行; t11 时刻,Task 1 执行完毕,继续调度尚未执行完毕的 Task 2;此刻低优先级的 Task 3 的 event 虽然也满足,但是优先级低,执行被推后; t12 时刻,Task 2 执行完毕,Task 3 得以被调度; t13 时刻,没有任务活动,调度 Idle 线程;

 在 **configUSE_PREEMPTION 和 configUSE_TIME_SLICING **都配置为 1 的时候,如果线程和 Idle 线程一样优先级,那么他们会被轮转调度:

上面的调度过程不在多说,Task 1 优先级最高,当满足他的 event 的时候,抢占其他任务执行,随后进入 blocked 状态;

在上面的例子中(有任务和 Idle 线程一样连续执行并且优先级一样),还有一个宏 configIDLE_SHOULD_YIELD,可能会导致调度器行为变化:

**configIDLE_SHOULD_YIELD **= 0,那么行为和上面的一样,也是默认情况; configIDLE_SHOULD_YIELD = 1,那么 Idle 线程会 loop 一次然后主动让出 CPU,如下所示:

 

如果 :

configUSE_PREEMPTION = 1 configUSE_TIME_SLICING = 0

这表示调度器支持抢占,但是对于同样优先级的任务,不会去轮转,比如:

可以看到 Task 1 优先级高,可以抢占低优先级;

但是 Task 2 和 Idle 优先级一样,但是得不到轮转的调度;

 

5.2、协作式调度

当配置如下:

configUSE_PREEMPTION = 0 configUSE_TIME_SLICING = any value

代表调度器会进行协作式调度,什么意思呢?如下所示:

Task 1 优先级最高,Task 2 其次,Task 3 优先级最低;

t1 时刻,Task 3 处于运行,Task 1 和 Task 2 处于阻塞; t2 时刻,Task 2 满足运行条件进入 Ready 状态,但是由于不支持抢占调度,所以无法执行,Task 3 继续执行; t3 时刻,Task 1 满足运行条件进入 Ready 状态,但是由于不支持抢占调度,所以无法执行,Task 3 继续执行; t4 时刻,Task 3 主动调用 taskYIELD() 函数,主动放弃 CPU,此刻调度器选择优先级最高的 Task 1 进行运行; t5 时刻,Task 1 执行完毕,进入 blocked,调度器调度 Task 2 运行; t6 时刻,Task 2执行完毕,进入 blocked,调度器调度 Task 3运行;

 

0条评�?
全部评论

关于博主

an actually real engineer

通信工程专业毕业,7年开发经验

技术栈:

精通c/c++

精通golang

熟悉常见的脚本,js,lua,python,php

熟悉电路基础,嵌入式,单片机

耕耘领域:

服务端开发

嵌入式开发

git

>

gin接口代码CURD生成工具

sql ddl to struct and markdown,将sql表自动化生成代码内对应的结构体和markdown表格格式,节省宝贵的时间。

输入ddl:
输出代码:

qt .ui文件转css文件

duilib xml 自动生成绑定控件代码

协议调试器

基于lua虚拟机的的协议调试器软件 支持的协议有:

串口

tcp客户端/服务端

udp 组播/udp节点

tcp websocket 客户端/服务端

软件界面

使用例子: 通过脚本来获得接收到的数据并写入文件和展示在界面上

下载地址和源码

duilib版本源码 qt qml版本源码 二进制包

webrtc easy demo

webrtc c++ native 库 demo 实现功能:

基于QT

webrtc摄像头/桌面捕获功能

opengl渲染/多播放窗格管理

janus meeting room

下载地址和源码

源码 二进制包

wifi,蓝牙 - 无线开关

实现功能:

通过wifi/蓝牙实现远程开关电器或者其他电子设备

电路原理图:

实物图:

深度学习验证工具

vtk+pcl 点云编辑工具

实现功能:

1. 点云文件加载显示(.pcd obj stl)

2. 点云重建

3. 点云三角化

4. 点云缩放

下载地址:

源码 二进制包

虚拟示波器

硬件实物图:

实现原理

基本性能

采集频率: 取决于外部adc模块和ebaz4205矿板的以太网接口速率,最高可以达到100M/8 约为12.5MPS

上位机实现功能: 采集,显示波形,存储wave文件。

参数可运行时配置

上位机:

显示缓冲区大小可调

刷新率可调节

触发显示刷新可调节

进程守护工具

基本功能:

1. 守护进程,被守护程序崩溃后自动重启。

2. 进程输出获取,显示在编辑框中。

二进制包

openblt 烧录工具

基本功能:

1. 加载openblt 文件,下载到具有openblt bootloader 运行的单片机中。

二进制包

opencv 功能验证工具(开源项目二次开发)

基本功能:

1. 插件化图像处理流程,支持自定义图像处理流程。 2. 完善的日志和权限管理

二进制包

又一个modbus调试工具

最近混迹物联网企业,发现目前缺少一个简易可用的modbus调试工具,本软件旨在为开发者提供一个简单modbus测试工具。
主打一个代码简单易修改。
特点:

1. 基于QT5

2. 基于libmodbus

3. 三方库完全跨平台,linux/windows。

二进制包

屏幕录制工具

1. 基于QT5

2. 基于ffmpeg

3. 支持自定义录屏

源代码

开源plutosdr 板卡

1. 完全开源

2. 提高固件定制服务

3. 硬件售价450 手焊产量有线

测试数据

内部DDS回环测试

接收测试

外部发送500MHZ FM波形

硬件原理图

matlab测试

2TRX版本

大部分plutosdr应用场景都是讲plutosdr板卡作为射频收发器来使用。
实际上plutosdr板卡本身运行linux 操作系统。是具有一定脱机运算的能力。 对于一些微型频谱检测,简单射频信号收发等应用完全可以将应用层直接实现在板卡上
相较于通过网卡或者USB口传输具有更稳定,带宽更高等优点。
本开源板卡由于了SD卡启动,较原版pluto支持了自定义启动应用的功能。
提供了应用层开发SDK(编译器,buildroot文件系统)。
通过usb连接电脑,经过RNDIS驱动可以近似为通过网卡连接
(支持固件的开发定制)。

二次开发例子

``` all:
arm-linux-gnueabihf-gcc -mfloat-abi=hard --sysroot=/root/v0.32_2trx/buildroot/output/staging -std=gnu99 -g -o pluto_stream ad9361-iiostream.c -lpthread -liio -lm -Wall -Wextra -lrt
clean:
rm pluto_stream

bsdiff算法补丁生成器

1. 官方bsdiff算法例子自带bzip压缩方式

2. 本例子没有压缩,直接生成补丁文件

3. 图形化界面基于DUILIB

二进制文件

版面分析即分析出图片内的具体文件元素,如文档标题,文档内容,文档页码等,本工具基于cnstd模型

Base64 Image

. 闽ICP备19002644号