基于嵌入式操作系统VxWorks的多任务并发程序设计(2) ――任务控制

简介:

基于嵌入式操作系统VxWorks的多任务并发程序设计(2

――任务控制
作者:宋宝华  e-mail:[email]21cnbao@21cn.com[/email]   出处:软件报

任务与任务状态

VxWorks 实时内核 Wind 提供了基本的多任务环境。对用户而言,宏观上看起来,多个任务同时在执行。而本质而言,在微观上,系统内核中的任务调度器总是在根据特定的调度策略让它们交替运行。系统调度器需要使用任务控制块( TCB) 数据结构来管理任务调度功能, TCB 被用来描述一个任务。 TCB 中存放了任务的上下文( context) 信息,主要包括程序计数器 PC CPU 内部寄存器、浮点寄存器、堆栈指针 SP 、任务信息等。每一任务都与一个 TCB 关联,当执行中的任务被停止时,任务的上下文信息需要被写入 TCB ;而当任务被重新执行时,必须要恢复这些上下文信息。
VxWorks 的一个任务可能处于如下几种状态:
Ready :就绪状态(不是运行状态),其他资源已经就绪,仅等待 CPU ,当获得 CPU 后,就进入 Running 状态;
Pended :阻塞状态,由于等待某些资源( CPU 除外)而阻塞;
Suspended :挂起状态,这种状态需要用 taskResume 才能恢复,主要用于调试。不会约束状态的转换,仅仅约束任务的执行;
Delayed :睡眠状态,任务以 taskDelay 主动要求等待一段时间再执行;
这些状态之间的转换关系如下:
任务状态转换
完成方式
Ready -> pended
通过 semTake()/msgQReceive() 调用
Ready -> delayed
通过 taskDelay()
ready -> suspended
通过 taskSuspend()
pended -> ready
通过其它任务对 semaGive()/msgQSend() 的调用
pended -> suspended
通过其它任务对 taskSuspend() 调用
delayed -> ready
延迟期满
delayed -> suspended
通过 taskSuspend() 调用
suspended -> ready
通过 taskResume()/taskActivate() 调用
suspended -> pended
通过其它任务的 taskResume() 调用
suspended -> delayed
通过其它任务的 taskResume() 调用
 
 

任务控制

5.1创建任务

VxWorks 程序员创建任务需使用如下 API
taskSpawn (char *name, int priority, int options, int stackSize,
                       FUNCPTR entryPt, int arg1, int arg2, int arg3,
                       int arg4, int arg5, int arg6, int arg7,
                       int arg8, int arg9, int arg10);
API 的参数定义如下:
name :任务名;
priority :任务优先级;
options :任务选项,下表给出了各种 option 及其含义:
选项
16 进制值
含义
VX_FP_TASK
0x0008
执行浮点协处理
VX_NO_STACK_FILL
0x0100
不对任务堆栈填充 0xee
VX_PRIVATE_ENV
0x0080
执行一个环境私有的任务
VX_UNBREAKABLE
0x0002
使任务不能断点
VX_DSP_TASK
0x0200
1 = DSP 协处理支持
VX_ALTIVEC_TASK
0x0400
1 = ALTIVEC 协处理支持
stacksize :任务堆栈大小;
main :任务入口函数;
arg1,…arg10 :任务入口函数参数
下面来看一个具体的例子:
1 :创建任务
/* includes */
#include "vxWorks.h"
#include "taskLib.h"
#include "sysLib.h"
 
 
int tid;
/* task function */
void myFunc(void)
{
  int i;
 
 
  printf("Hello, I am task %d\n", taskIdSelf()); /* Print task Id */
  for (i = 0; i < 10; i++)
  {
    printf("%d ", i);
    taskDelay(sysClkRateGet ( ) / 2);
  }
}
/* user entry */
void user_start()
{
  printf("ready to begin a new task\n");
  tid = taskSpawn("myTask", 90, VX_NO_STACK_FILL, 2000, (FUNCPTR) myFunc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
程序运行,在 VxSim 上输出:
Hello, I am task 14870080
0 1 2 3 4 5 6 7 8 9
taskDelay(sysClkRateGet ( ) / 2) 语句的含义为将任务延迟 0.5S ,因此, 0 1 9 的数字输出之间间隔 0.5S
要特别注意 taskSpawn 函数的 options 参数,在如下几种情况下我们都要将其它 options  VX_FP_TASK 做“按位或”操作使得任务支持浮点运算(如果仅包含此选项,则不需进行或操作):
1 )执行浮点操作;
2 )调用返回任何浮点数的函数;
3 )调用参数为浮点数的函数。
例如下列程序启动任务的方式就不正确:
2 :创建浮点支持任务
/* task including float calculate */
void floatTask(void)
{
  printf("%f", 100 / 30.0);
}
/* user entry */
void user_start()
{
  taskSpawn("floatTask", 90, VX_NO_STACK_FILL, 2000, (FUNCPTR) floatTask, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
应该将对 taskSpawn 函数调用的代码改为:
taskSpawn("floatTask", 90, VX_NO_STACK_FILL | VX_FP_TASK, 2000, floatTask, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

5.2 终止任务

exit( )  :终止当前任务。这个函数是不安全的,任务终止后,其所占据的内存空间并未释放,请看下面的程序:
3 :任务退出
/* includes */
#include "vxWorks.h"
#include "taskLib.h"
#include "sysLib.h"
 
 
int tid;
/* task function */
void myFunc(void)
{
  int i;
 
 
  printf("Hello, I am task %d\n", taskIdSelf()); /* Print task Id */
  for (i = 0; i < 5; i++)
  {
    printf("%d ", i);
    taskDelay(sysClkRateGet() / 2);
  }
  exit(0);
  for (i = 5; i < 10; i++)
  {
    printf("%d ", i);
    taskDelay(sysClkRateGet() / 2);
  }
}
 
 
/* user entry */
void user_start()
{
  printf("ready to begin a new task\n");
  tid = taskSpawn("myTask", 90, 0x100, 2000, (FUNCPTR) myFunc, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0);
}
这次程序仅仅输出:
Hello, I am task 14868640
0 1 2 3 4
这意味着 exit(0) 语句之后的循环 for (i = 5; i < 10; i++) 没有被执行。
 
extern STATUS taskDelete (int tid);
 
 
4 :删除任务
/* includes */
#include "vxWorks.h"
#include "taskLib.h"
#include "sysLib.h"
 
 
int tid;
/* task function */
void myFunc(void)
{
  int i;
 
 
  printf("Hello, I am task %d\n", taskIdSelf()); /* Print task Id */
  for (i = 0; i < 10; i++)
  {
    printf("%d ", i);
    taskDelay(sysClkRateGet() / 2);
  }
}
 
 
/* another task function:delete my task */
void delMyTaskFunc(void)
{
  taskDelay(sysClkRateGet() *4);
  printf("ready to delete task\n");
  taskDelete(tid);
}
 
 
/* user entry */
void user_start()
{
  printf("ready to begin new tasks\n");
  tid = taskSpawn("myTask", 90, 0x100, 2000, (FUNCPTR) myFunc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  taskSpawn("delMyTask", 90, 0x100, 2000, (FUNCPTR)delMyTaskFunc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
运行输出:
Hello, I am task 14868640
0 1 2 3 4 5 6 7 ready to begin a new task
程序为运行输出 8 9 ,这是因为在此之前, myTask 已经被另一个任务―― delMyTask 删除。
任务可能被 taskDelete() 调用删除掉,但这一行为也不一定是安全的。如果我们删除一个获得了某些资源(如二进制信号量等)的任务,则对应的资源将不被释放,到站其它正在等待该资源的任务永远不能获得资源,系统会挡掉。我们可以用  taskSafe()  taskUnsafe () 来保护这种区域,例如:
taskSafe ();
semTake (semId, WAIT_FOREVER);
/* Block until semaphore available */
. .   . .   critical region .
semGive (semId);   semGive (semId);   
/* Release semaphore */
taskUnsafe ();

5.3 延迟任务

taskdelay() 提供了一个简单的任务睡眠机制,常用于需要定时 / 延时机制的应用中。它的原型是:
STATUS taskDelay(int ticks /* number of ticks to delay task */);
可以看出使用该函数实现延时的单位为节拍( tick )。在 VxWorks 下通常以如下方式调用 taskDelay() 函数:
taskDelay(sysClkRateGet()*n);
其中的 n 是要延迟的时间,以秒为单位。其中的 sysClkRateGet(int ticks /* number of ticks every second */) 函数返回系统的时钟速率,单位是 tick / 每秒。操作系统每秒的 tick 数可以利用 sysClkRateSet() 函数设置。

5.4 挂起/恢复/重启任务

我们可以使用 taskSuspend() 函数挂起一个任务的运行,这个任务只有获得对应的 taskResume() 后才能再次运行,这两个 API 的原型为:
extern STATUS taskSuspend (int tid);
extern STATUS taskResume (int tid);
5 :挂起 / 恢复任务
/* includes */
#include "vxWorks.h"
#include "taskLib.h"
#include "sysLib.h"
 
 
int tid;
/* task function */
void myFunc(void)
{
  int i;
 
 
  printf("Hello, I am task %d\n", taskIdSelf()); /* Print task Id */
  for (i = 0; i < 10; i++)
  {
    printf("%d ", i);
    taskDelay(sysClkRateGet() / 2);
  }
}
 
 
/* suspend and resume task */
void suspendResumeMyTask(void)
{
  taskDelay(sysClkRateGet() *3);
  taskSuspend(tid);
  printf("my task is suspended\n");
  taskDelay(sysClkRateGet() *3);
  taskResume(tid);
}
 
 
/* user entry */
void user_start()
{
  printf("ready to begin new tasks\n");
  tid = taskSpawn("myTask", 90, 0x100, 2000, (FUNCPTR) myFunc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  taskSpawn("suspendResumeMyTask", 90, 0x100, 2000, (FUNCPTR) suspendResumeMyTask, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0);
}
运行输出:
Hello, I am task 17753664
0 1 2 3 4 5 my task is suspended
6 7 8 9
这个程序运行 3 秒后, suspendResumeMyTask 任务挂起了 myTask ,输出“ my task is suspended ”。 suspendResumeMyTask 本身延迟 3 秒后恢复 myTask ,使得 myTask 再次输出“ 6 7 8 9 ”。显然,“ 6 7 8 9 ”与“ 0 1 2 3 4 5的输出之间间隔了3 秒以上的时间。
如果我们将上述程序改为:
6 :重启任务
/* includes */
#include "vxWorks.h"
#include "taskLib.h"
#include "sysLib.h"
 
 
int tid;
/* task function */
void myFunc(void)
{
  int i;
 
 
  printf("Hello, I am task %d\n", taskIdSelf()); /* Print task Id */
  for (i = 0; i < 10; i++)
  {
    printf("%d ", i);
    taskDelay(sysClkRateGet() / 2);
  }
}
 
 
/* reset task */
void resetMyTask(void)
{
  taskDelay(sysClkRateGet() *3);
  printf("my task will be reseted\n");
  taskRestart(tid);
}
 
 
/* user entry */
void user_start()
{
  printf("ready to begin new tasks\n");
  tid = taskSpawn("myTask", 90, 0x100, 2000, (FUNCPTR) myFunc, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0);
  taskSpawn("resetMyTask", 90, 0x100, 2000, (FUNCPTR)resetMyTask, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
运行输出:
Hello, I am task 17753664
0 1 2 3 4 5 my task will be reseted
Hello, I am task 17753664
0 1 2 3 4 5 6 7 8 9
我们可以使用 taskRestart() 函数重新启动一个任务,不管任务当前处于什么状态,它都会被重新开始。该 API 的原型是:
extern STATUS taskRestart (int tid);
在例 6 中,程序运行 3 秒后 resetMyTask 启动,它复位了 myTask ,因此 myTask 被重新执行,“ Hello, I am task 17753664 ”以及“ 0 1 2 3 4 5被再次输出。

5.5任务钩子

        有过 Windows 钩子( Hook )编程经验的读者应该对其概念并不陌生, Hook 作为回调函数,当被挂接后。操作系统发生特定的事情时,将触发这个 Hook 回调函数的执行。 VxWorks 也有钩子的概念,不过比 Windows 要简单许多,主要有 taskCreateHook taskDeleteHook taskSwitchHookAdd ,可以通过如下 6 API 来添加和删除这三种 Hook
STATUS taskCreateHookAdd (FUNCPTR createHook /* routine to be called when a task is created */ );
STATUS taskCreateHookDelete (FUNCPTR createHook /* routine to be deleted from list */);
STATUS taskSwitchHookAdd (FUNCPTR switchHook /* routine to be called at every task switch */);
STATUS taskSwitchHookDelete (FUNCPTR switchHook /* routine to be deleted from list */);
STATUS taskDeleteHookAdd (FUNCPTR deleteHook /* routine to be called when a task is deleted */);
STATUS taskDeleteHookDelete (FUNCPTR deleteHook /* routine to be deleted from list */);
请看例程:
7 :任务钩子 Hook
/* includes */
#include "vxWorks.h"
#include "taskLib.h"
#include "taskHookLib.h"    //taskHook 所对应的库
 
 
/* task function */
void myFunc(void)
{
  int i;
  printf("Hello, I am task %d\n", taskIdSelf()); /* Print task Id */
}
 
 
/* taskCreatHook */
void myTaskHook(void)
{
  printf("task hook function called\n");
}
 
 
/* user entry */
void user_start()
{
  taskCreateHookAdd( (FUNCPTR) myTaskHook);
  taskSpawn("myTask", 90, 0x100, 2000, (FUNCPTR) myFunc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
运行输出:
task hook function called
Hello, I am task 14868640

5.6 其它重要API

与任务控制相关的其它重要 API 还有:
 
extern STATUS        taskOptionsSet (int tid, int mask, int newOptions);
 
extern STATUS        taskOptionsGet (int tid, int *pOptions);
 
extern char *      taskName (int tid);
 
extern int    taskNameToId (char *name);
 
extern STATUS        taskIdVerify (int tid);
 
extern int    taskIdSelf (void);
 
extern BOOL    taskIsReady (int tid);
 
extern BOOL    taskIsSuspended (int tid);
 
extern WIND_TCB *taskTcb (int tid);
 
STATUS taskPrioritySet (int tid, /* task ID */ int newPriority /* new priority */ );
 
extern STATUS        taskLock (void);
extern STATUS        taskUnlock (void);




 本文转自 21cnbao 51CTO博客,原文链接:http://blog.51cto.com/21cnbao/120730,如需转载请自行联系原作者


相关文章
|
3月前
|
安全 Unix Linux
Unix是一个多用户、多任务的操作系统
Unix是一个多用户、多任务的操作系统
234 3
|
2月前
|
存储 iOS开发 MacOS
MacOS环境-手写操作系统-33-多任务多窗口
MacOS环境-手写操作系统-33-多任务多窗口
51 0
|
3月前
|
Web App开发 Linux iOS开发
操作系统的演变:从单任务到多核并发
在数字时代的浪潮中,操作系统作为计算机硬件与应用程序之间的桥梁,其发展历史充满了创新与变革。本文将带领读者穿越时空,探索操作系统如何从简单的单任务处理演化为今天能够高效管理多核处理器的复杂系统。我们将一窥各个时代下操作系统的设计哲学,以及它们是如何影响现代计算的方方面面。加入我们的旅程,一起见证技术的力量如何在每次迭代中重塑世界。
46 7
|
3月前
|
机器学习/深度学习 人工智能 算法
操作系统的未来:从多任务到深度学习的演变之路
本文将探讨操作系统如何从处理简单多任务发展到支持复杂的深度学习任务。我们将分析现代操作系统面临的新挑战,以及它们如何适应人工智能和大数据时代的要求。文章不仅回顾过去,也展望未来,思考操作系统在技术演进中的角色和方向。
69 3
|
3月前
|
人工智能 算法 数据挖掘
操作系统的演变:从单任务到多任务的旅程
操作系统(OS)是计算机系统的核心,它管理硬件资源、提供用户界面并运行应用程序。本文将探讨操作系统如何从单任务环境演变为支持多任务的环境,包括这一过程中的技术挑战和解决方案。我们将看到,随着计算需求的增长,操作系统必须适应更复杂的任务管理和资源分配策略,以提高效率和用户体验。通过这个旅程,我们不仅能够理解操作系统的发展,还能洞察未来可能的趋势。
53 5
|
4月前
|
缓存 安全 数据库
探索后端开发的核心原则与实践操作系统的未来:从多任务处理到智能优化
【8月更文挑战第23天】在数字化时代的浪潮中,后端开发作为技术架构的支柱,承载着数据处理、业务逻辑实现和系统性能优化的关键任务。本文将深入探讨后端开发的几大核心原则,包括模块化设计、性能优化、安全性强化及可维护性提升,旨在为读者揭示如何构建一个健壮、高效且安全的后端系统。通过分析这些原则背后的理念及其在实际开发中的应用,本文意在启发读者思考如何在不断变化的技术环境中,持续优化后端开发实践,以适应新的挑战和需求。
|
4月前
|
调度 UED
操作系统中的多任务处理机制
【8月更文挑战第23天】在数字时代,操作系统的核心功能之一是多任务处理。它允许用户同时运行多个程序,优化资源使用,并提高生产效率。本文将深入探讨操作系统如何实现多任务处理,以及这一机制对用户体验和系统性能的影响。通过理解多任务处理的工作原理,用户可以更好地管理计算资源,提升个人和组织的工作效率。
|
1月前
|
安全 Linux 数据安全/隐私保护
Vanilla OS:下一代安全 Linux 发行版
【10月更文挑战第30天】
58 0
Vanilla OS:下一代安全 Linux 发行版
|
1月前
|
NoSQL Linux PHP
如何在不同操作系统上安装 Redis 服务器,包括 Linux 和 Windows 的具体步骤
本文介绍了如何在不同操作系统上安装 Redis 服务器,包括 Linux 和 Windows 的具体步骤。接着,对比了两种常用的 PHP Redis 客户端扩展:PhpRedis 和 Predis,详细说明了它们的安装方法及优缺点。最后,提供了使用 PhpRedis 和 Predis 在 PHP 中连接 Redis 服务器及进行字符串、列表、集合和哈希等数据类型的基本操作示例。
57 4
|
1月前
|
人工智能 安全 Linux
下一篇
DataWorks