【uTenux实验】任务管理
任务就是一个无限循环。uTenux提供的任务管理功能是很强大的,包括建立和删除一个任务,启动或退出任务,取消一个任务的启动请求,改变任务的优先级和査询任务状态,使任务进人睡眠状态和唤醒状态,取消唤醒请求,强制释放任务等待状态,使任务状态变成挂起状态、延迟调用任务的执行和禁止任务等待状态。
任务是一个通过ID来识别的对象,每个任务都有基础优先级和当前优先级,可用来控制任务的执行次序
任务管理的核心是调度。uTenux会根据创建任务时为任务设置的初始属性和任务运行是获得的动态属性,对任务进行调度。
创建任务需要为提供T_CTSK类型的任务结构体。这个结构体的定义如下:
typedef struct t_ctsk {
    VP                  exinf;                   /* 额外信息,OS不关注*/
    ATR                 tskatr;                  /* 任务属性*/
    FP                  task;                    /* 任务服务函数入口*/
    PRI                 itskpri;                 /* 初始优先级*/
    W                   stksz;                   /* 用户栈大小 (byte) */
    UB                  dsname[8];               /* Object name */
    VP                  bufptr;                  /* 用户缓存地址*/
} T_CTSK;
任务的属性是一个unsigned long类型的二进制数,它的低位是系统属性,高位是具体实现相关的信息。任务属性有以下几个方面:
tskatr :=(TA_ASM||TA_HLNG)|[TA_USERBUF]|[TA_DSNAME]|(TA_RNG0)
TA_ASM 表示任务是用汇编语言编写的
TA_HLNG 表示任务是用高级语言编写的
TA_USERBUF 表示任务是用用户指定的内存区域作为栈空间
TA_DSNAME 指定DS对象名
TA_RNGn 指定任务运行在保护级别n
任务结构体的详细介绍,可参考uTenux的内核规范。
将任务结构体传递给任务启动函数tk_cre_tsk就可以创建一个任务。
ID tskid=tk_cre_tsk(T_CTSK* pk_ctsk);
返回值是这个任务的ID,可以作为任务的索引。创建任务只是为任务分配控制块TCB,并不能是任务立即运行或就绪,此时任务处于静止状态。要想是任务变为就绪状态,还需要使用tk_sta_tsk手动启动任务:
ER ercd= tk_sta_tsk(ID tskid,INT stacd);
其中,tskid为创建任务时候获得的任务ID,stacd是任务的启动代码。stacd用于在启动时传递给任务的参数,这个参数可从启动任务中查询得到,使用这个特性可进行简单的消息传递。
有了以上的概念,就可以开始今天的实验了。
这个实验参考这uTenux提供的实力sample 01.Task。器质性流程如下所述:
1、在应用程序入口main函数中进行硬件初始化,之后启动操作系统并创建一个任务initctsk。
2、在initctsk函数中调用usermain();函数,并通过usermain函数继续调用TaskSample函数。进入实验的主要部分。
3、在TaskSample中,首先创建三个任务,任务ID分别为:TaskID_A、TaskID_B、TaskID_C。优先级分别为24,26,28.之后启动TaskC。
4、在TaskC的服务函数中,首先输出一段信息,然后启动TaskA。有余TaskA的优先级较高,立即抢断TaskC开始运行。
5、TaskA的服务函数中,完成一些信息的输出,之后TaskA进入休眠状态。TasKC重新获得最高优先权开始运行。
6、TaskC恢复运行后输出一段信息,然后就启动TaskB。同样TaskB也会抢断TaskC的开始运行。
7、TaskB执行一些动作之后,也会进入休眠状态。TaskC继续执行。进入一个循环。
8、实验通过串口进行输出。用到的输出函数,参见http://www.cnblogs.com/zyqgold/p/3161753.html
实验的主要代码如下:
//文件TaskSample.c
#include "TaskSample.h"
#include <dev/ts_devdef.h> void TaskSampleTaskA(W stacd,VP exinf);
void TaskSampleTaskB(W stacd,VP exinf);
void TaskSampleTaskC(W stacd,VP exinf); static ID TaskID_A;
static ID TaskID_B;
static ID TaskID_C; ER TaskSample( void)
{
ER ercd=E_OK;
T_CTSK ctsk;
//创建任务A
ctsk.exinf = NULL;
ctsk.tskatr = TA_HLNG | TA_RNG0 | TA_DSNAME;
ctsk.task = (FP)&TaskSampleTaskA;
ctsk.itskpri = 24;
ctsk.stksz = 512;
strcpy(ctsk.dsname,"TaskA..");
ctsk.bufptr = NULL;
TaskID_A = tk_cre_tsk(&ctsk);
if(TaskID_A < E_OK)
{
ercd = TaskID_A;
return ercd;
}
//创建任务B
ctsk.exinf = NULL;
ctsk.tskatr = TA_HLNG | TA_RNG0 | TA_DSNAME;
ctsk.task = (FP)&TaskSampleTaskB;
ctsk.itskpri = 26;
ctsk.stksz = 512;
strcpy(ctsk.dsname,"TaskB..");
ctsk.bufptr = NULL;
TaskID_B = tk_cre_tsk(&ctsk);
if(TaskID_B < E_OK)
{
ercd = TaskID_B;
return ercd;
}
//创建任务C
ctsk.exinf = NULL;
ctsk.tskatr = TA_HLNG | TA_RNG0 | TA_DSNAME;
ctsk.task = (FP)&TaskSampleTaskC;
ctsk.itskpri = 28;
ctsk.stksz = 512;
strcpy(ctsk.dsname,"TaskC..");
ctsk.bufptr = NULL;
TaskID_C = tk_cre_tsk(&ctsk);
if(TaskID_C < E_OK)
{
ercd = TaskID_C;
return ercd;
} tm_putstring((UB*)"Now start task C\n");
tk_sta_tsk(TaskID_C,4); return E_OK;
} void TaskSampleTaskA(W stacd,VP exinf)
{
while(1)
{
tm_putstring((UB*)"This is in TaskA\n");
tm_putstring((UB*)"Task_A will sleep\n");
tk_slp_tsk(1000);
}
} void TaskSampleTaskB(W stacd,VP exinf)
{
while(1)
{
tm_putstring((UB*)"Task_B is running\n");
tm_putstring((UB*)"****************\n");
tm_putstring((UB*)"Task_B will sleep\n");
tk_slp_tsk(500);
}
} void TaskSampleTaskC(W stacd,VP exinf)
{
tm_putstring((UB*)"TaskC will start task A\n");
tk_sta_tsk(TaskID_A,0);
tm_putstring((UB*)"TaskC will start task B\n");
tk_sta_tsk(TaskID_B,0);
tm_putstring((UB*)"Input Cmd,'e' for exit\n");
while(1)
{
if('e' == tm_getchar(-1))
{
break;
}
else
{
tm_putstring((UB*)"**************************************\n");
tm_putstring((UB*)"task A will wup\n");
tk_wup_tsk(TaskID_A);
tm_putstring((UB*)"task B will wup\n");
tk_wup_tsk(TaskID_B);
}
tm_putstring((UB*)"Input Cmd,'e' for exit\n");
}
tm_putstring((UB*)"Task A will stop\n");
tk_ter_tsk(TaskID_A);
tk_del_tsk(TaskID_A);
tm_putstring((UB*)"Task B will stop\n");
tk_ter_tsk(TaskID_B);
tk_del_tsk(TaskID_B);
tm_putstring((UB*)"Task C will stop\n");
tk_ext_tsk();
}
实验的输出如下:
----------------------------------------------------
        micro Tenux Version 1.6.00(build 0180)      
            Supported MCU is ST STM32F407VG         
  Copyright(c) 2008-2013 by Dalian uLoong Co.,Ltd.  
----------------------------------------------------
Now start task C
TaskC will start task A
This is in TaskA
Task_A will sleep
TaskC will start task B
Task_B is running
****************
Task_B will sleep
Input Cmd,'e' for exit
**************************************
task A will wup
This is in TaskA
Task_A will sleep
task B will wup
Task_B is running
****************
Task_B will sleep
Input Cmd,'e' for exit
Task A will stop
Task B will stop
Task C will stop
Push any key to shutdown the micro Tenux.
<< SYSTEM SHUTDOWN >>
【附1】uTenux的任务状态
1、运行状态:当前任务正在运行
2、就绪状态:任务已经完成运行前的准备,但由于有更高优先权的任务正在运行,使得它不能运行
3、等待状态:由于运行的条件未达到而导致任务不能运行。分三种:
1、等待状态:等待资源
2、挂起状态:执行被其他任务强行中断。 等待优先权
3、等待挂起状态; 任务在同一时间内既在等待状态,也在挂起状态
4、静止状态:任务还未启动或者已经完成执行的状态
5、不存在状态:任务未在系统中注册
【附2】uTenux提供的任务API
tk_sta_sys 启动内核。这个东西是uT自己加进去的,必须在其他系统调用之前执行。需要有一个任务做完参数。启动内核时会立即创建和启动这个任务,即将CPU的控制权交给这个任务。
tk_ext_sys 退出内核
tk_sta_tsk 启动任务,将任务从静止状态转换成就绪状态。需要提供TaskID和另外一个参数stacd。参数Stacd没有什么大用处。
tk_slp_tsk 将任务休眠。参数tmout指的是OS时钟的周期数。如果这个周期结束前调用了tk_wup_tsk,那么任务被唤醒。如果在tmout周期内没有收到tk_wup_tsk唤醒,那么任务自动唤醒。但会返回一个错误代码。
tk_wup_tsk 唤醒由tk_slp_tsk休眠的任务。将任务从等待状态释放
tk_dly_tsk 暂停调用这个函数的任务的执行。但是这时,这个任务的状态还是等待状态而不是休眠状态。。如果要提前终止这个等待时间,可以用tk_rel_wai来执行。
tk_ter_tsk 终止其他任务。强制将tskid指定的任务变为静止状态。任务使用的资源不会自动释放。
tk_del_tsk 删除任务。将任务从静止状态转为不存在状态。所删除的任务必须是静止状态
tk_ext_tsk 退出调用任务。就是调用这个函数的任务自己把自己退出了。自杀,变成静止状态。但是这个函数不会释放任务所使用的资源,需要手动释放。
【附3】关于示例中任务的退出
uTenux示例中一般都会有两个任务TaskA和TaskB。刚开始做实验的时候曾经问过zhangzl一个问题:当所有的任务都进入等待状态之后,系统是不是就退出了。当时有这个问题,是因为我将两个任务都休眠了之后,OS确实会返回到等待退出状态。今天再次看了看代码,发现示例工程中OS的退出不是因为这个问题!整个示例工程的执行流程是这样的:
1、在main函数中,调用tk_sta_sys((T_CTSK *)&initctsk);启动OS。OS的第一个任务是initctsk
2、在initctsk中调用usermain()来处理其他用户任务,比如TaskA、TaskB。Inittask是一个任务,usermain相当于一个函数。
3、在usermain中调用TaskSample启动和处理其他任务。由于initctsk的优先级最低,当TaskSample中所有任务都不处于等待状态时,initctsk就会继续执行。执行TaskSample之后的代码,只有一行:tk_ext_sys(); 就是退出内核
4、到此,内核就退出了。
5、如果将tk_ext_sys();换成while(1);那么当TaskA、TaskB超时苏醒过来的时候,就会抢断initctsk继续执行。
这个问题归根结底就是刚开始时候,不太明白任务调用方法:第优先级被高优先级抢断,返回时还会回到被抢断的地方继续执行。
【uTenux实验】任务管理的更多相关文章
- 【uTenux实验】写在开始实验之前
		
1.使用的uTenux内核代码:http://www.uloong.cc/cn/download/uTenux_V1.6.00r180.zip 2.uTenux的特性: 1.微内核 2.开放源码.完 ...
 - 【uTenux实验】信号量
		
信号量(semaphore)是一个用来指示可用的资源并将可用资源的数量以数值的形式表示出来的对象.当使用一组资源时,信号量用来实现互斥控制和同步.uTenux提供了信号量出来的API,可以很方便地使用 ...
 - 【uTenux实验】事件标志
		
事件标志是一个用来实现同步的对象,由多个位组成,用作指示对应事件存在的标志.事件标志由用来指示对应事件存在的位模式(bitpattern)和一个等待事件标志的任务队列组成. uTenux提供了一组AP ...
 - 【uTenux实验】邮箱
		
邮箱是一个通过在系统(共享)内存空间传递消息来实现同步和通信的对象.uTenux中每个邮箱都包含一个用来发送消息的消息队列和一个用于等待接收消息的任务队列,其使用邮箱功能的消息内容放置在发送方和接收方 ...
 - 【uTenux实验】互斥体
		
互斥体,维基百科中交互斥锁.其定义是这样的:互斥锁(英语:英语:Mutual exclusion,缩写 Mutex)是一种用于多线程编程中,防止两条线程同时对同一公共资源(比如全局变量)进行读写的机制 ...
 - 【uTenux实验】消息缓冲区
		
uTenux的消息缓冲区是一个通过传递大小可变的消息来实现同步和通信的对象. 消息缓冲区由三部分组成:1.待发消息队列 2.等接收消息的任务队列 3.用来保存缓冲消息的空间. 和信号相比,消息队列 ...
 - 【uTenux实验】集合点端口
		
这个是头一次接触的概念.比较不好理解.内核规范中的说明就要20页! 看了王总写的uTenux内核规范之后,有那么一点明白了但理解不深. 集合点端口就像每次工作前的收集情况会.首长下达收集情况指令,各个 ...
 - 【uTenux实验】内存池管理(固定内存池和可变内存池)
		
1.固定内存池管理实验 内存管理是操作系统的一个基础功能.uTenux的内存池管理函数提供了基于软件的内存池管理和内存块分配管理.uTenux的内存池有固定大小的内存池和大小可变的内存池之分,它们被看 ...
 - 【uTenux实验】时间管理(系统时间/周期性处理/警报处理)
		
1.系统时间管理 系统时间管理函数用来对系统时间进行操作,是OS的一个基础性的东西.个人认为,设置系统时间和获取系统时间对OS来说基本是可有可无的. uTenux提供了三个系统时间相关API.分别用于 ...
 
随机推荐
- Keeplived配置Nginx双机高可用
			
一.简介不管是Keepalived还是Heartbeat做高可用,其高可用,都是站在服务器脚本去说的高可用,而不是服务的角度.也就是说,如果服务器DOWN机或者网络出现故障,高可用是可以实现自动切换的 ...
 - JavaWeb chapter9 JSP基础
			
1. Servlet的缺陷 一个动态网页中,大部分内容都是HTML代码等固定不变的内容,编写和修改HTML非常不方便,令人厌恶: 部署Servlet是繁琐而且容易出错的任务:(Servlet3.0规 ...
 - code of  C/C++  (1)
			
去年,王老师拷贝给我一些代码,非常感激,老爷子的水平我这个小辈只能仰视,代码都是来自他所教的课程,有些课程因为这几年据说太难都给取消掉了,实在是 我们学校的损失. C/C++代码都是在讲述一些非常基本 ...
 - C++ / CLI 调用 C++ /Native 随记
			
C# 封装 原生C++ 方法:1.C++ CLR(托管) 调用 C++(原生)2.C#调用C++ CLR , 注意各个平台编译版本需一致.3.C# 默认编绎生成版本是 any cpu , 需修改成 ...
 - Android之View和SurfaceView
			
Android之View和SurfaceView Android游戏当中主要的除了控制类外就是显示类View.SurfaceView是从View基类中派生出来的显示类.android游戏开发中常用的三 ...
 - sqlite入门
			
SQLite官网: https://www.sqlite.org/index.html 1. 下载请到https://www.sqlite.org/download.html下载相应平台的sqlite ...
 - linux,python 常用的处理log的命令
			
一般的log文件都是需要过滤 ps:管道符| 管道符前面的输出值 grep 过滤查找 将是error的log过滤显示 grep '221.2.100.138' web.access.log gr ...
 - PAT (Basic Level) Practise:1032. 挖掘机技术哪家强
			
[题目链接] 为了用事实说明挖掘机技术到底哪家强,PAT组织了一场挖掘机技能大赛.现请你根据比赛结果统计出技术最强的那个学校. 输入格式: 输入在第1行给出不超过105的正整数N,即参赛人数.随后N行 ...
 - pyhton 27 pip命令无法使用   没有Scripts文件夹  的解决方法
			
1 安装了setuptools http://jingyan.baidu.com/article/fb48e8be52f3166e622e1400.html 2 用ez_setup.py安装了setu ...
 - Android使用echarts框架的K线图
			
百度echarts框架还是比较强大的,之前有尝试使用它,但毕竟主要使用于web网页端,效果不是很好,所以最终还是取消使用echarts 但之前在使用的过程中遇到些问题,虽然解决很简单,但也花了我不少时 ...