vxworks系统及函数详解

更新时间:2024-01-26 00:31:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

VxWork介绍及编程

VxWork介绍及编程

一.嵌入式操作系统VxWorks简介

VxWorks操作系统是美国WindRiver公司于1983年设计开发的一种嵌入式实时操作系统(RTOS),是嵌入式开发环境的关键组成部分。良好的持续发展能力、高性能的内核以及友好的用户开发环境,在嵌入式实时操作系统领域占据一席之地。它以其良好的可靠性和卓越的实时性被广泛地应用在通信、军事、航空、航

天等高精尖技术及实时性要求极高的领域中,如卫星通讯、军事演习、弹道制导、飞机导航等。在美国的 F-16、FA-18 战斗机、B-2 隐形轰炸机和爱国者导弹上,甚至连1997年4月在火星表面登陆的火星探测器上也使用到了VxWorks。

实时操作系统和分时操作系统的区别

从操作系统能否满足实时性要求来区分,可把操作系统分成分时操作系统和实时操作系统。

分时操作系统按照相等的时间片调度进程轮流运行,分时操作系统由调度程序自动计算进程的优先级,而不是由用户控制进程的优先级。这样的系统无法实时响应外部异步事件。 实时操作系统能够在限定的时间内执行完所规定的功能,并能在限定的时间内对外部的异步事件作出响应。 分时系统主要应用于科学计算和一般实时性要求不高的场合。实时性系统主要应用于过程控制、数据采集、通信、多媒体信息处理等对时间敏感的场合。

VxWorks的特点

? 可靠性

操作系统的用户希望在一个工作稳定,可以信赖的环境中工作,所以操作系统的可靠性是用户首先要考虑的问题。而稳定、可靠一直是VxWorks的一个突出优点。自从对中国的销售解禁以来,VxWorks以其良好的可靠性在中国赢得了越来越多的用户。

? 实时性

实时性是指能够在限定时间内执行完规定的功能并对外部的异步事件作出响应的能力。实时性的强弱是以完成规定功能和作出响应时间的长短来衡量的。

VxWorks 的实时性做得非常好,其系统本身的开销很小,进程调度、进程间通信、中断处理等系统公用程序精练而有效,它们造成的延迟很短。VxWorks 提供的多任务机制中对任务的控制采用了优先级抢占(Preemptive Priority Scheduling)和轮转调度(Round-Robin Scheduling)机制,也充分保证了可靠的实时性,使同样的硬件配置能满足更强的实时性要求,为应用的开发留下更大的余地。

? 可裁减性

用户在使用操作系统时,并不是操作系统中的每一个部件都要用到。例如图形显示、文件系统以及一些设备驱动在某些嵌入系统中往往并不使用。

VxWorks 由一个体积很小的内核及一些可以根据需要进行定制的系统模块组成。VxWorks 内核最小为 8kB,即便加上其它必要模块,所占用的空间也很小,且不失其实时、多任务的系统特征。由于它的高度灵活性,用户可以很容易地对这一操作系统进行定制或作适当开发,来满足自己的实际应用需要。

对一个实时内核的要求

一个实时操作系统内核需满足许多特定的实时环境所提出的基本要求,这些包括:

多任务:由于真实世界的事件的异步性,能够运行许多并发进程或任务是很重要的。多任务

提供了一个较好的对真实世界的匹配,因为它允许对应于许多外部事件的多线程执行。系统

内核分配CPU给这些任务来获得并发性。

抢占调度:真实世界的事件具有继承的优先级,在分配CPU的时候要注意到这些优先级。

基于优先级的抢占调度,任务都被指定了优先级,在能够执行的任务(没有被挂起或正在等待资源)中,优先级最高的任务被分配CPU资源。换句话说,当一个高优先级的任务变为可

执行态,它会立即抢占当前正在运行的较低优先级的任务。 任务间的通讯与同步:在一个实时系统中,可能有许多任务作为一个应用的一部分执行。系统必须提供这些任务间的快速且功能强大的通信机制。内核也要提供为了有效地共享不可

抢占的资源或临界区所需的同步机制。

任务与中断之间的通信:尽管真实世界的事件通常作为中断方式到来,但为了提供有效

的排队、优先化和减少中断延时,我们通常希望在任务级处理相应的工作。所以需要杂任务

级和中断级之间存在通信。

二.系统编程方法

了解系统编程对程序员来说尤为重要。根据Drew个人的经验基本上操作系统编程都是类似的,认真读懂一种,就很容易的理解另一种。

下面是Drew翻的VxWorks programmer guide中的基本内容,有一些内容是Drew个人的理解。理解这些内容对实时操作编程非常重要。

实时系统主要包括:多任务调度(采用优先级抢占方式),任务间的同步和进程间通信机制。 一个多任务环境允许实时应用程序以一套独立任务的方式构筑,每个任务拥有独立的执行线程和它自己的一套系统资源。进程间通信机制使得这些任务的行为同步、协调。 wind使用中断驱动和优先级的方式。它缩短了上下文转换的时间开销和中断的时延。在 VxWorks 中,任何例程都可以被启动为一个单独的任务,拥有它自己的上下文和堆栈。还有一些其它的任务机制可以使任务挂起、继续、删除、延时或改变优先级。

另一个重要内容是:硬件中断处理。硬件产生中断,统治系统调用相应的中断历程(ISR),位是系统得到尽快的响应,ISR在它自己独立的上下文和堆栈中运行.它的优先级高于任何任务优先级.

[

size=-1]Task State Transitions

中断延迟(Interrupt Latency) 中断延迟是指从硬件中断发生到开始执行中断处理程序第一

条指令之间的这段时间。

优先级驱动(Priority-Driven) 优先级驱动是指多任务系统中,当前运行任务总是具有最高优先级的就绪任务。

?

多任务调度

两种方式: 优先抢占和轮转调度(Preemptive Priority,Round-Robin Scheduling).

优先抢占(Preemptive Priority): 每一个任务都有一个优先级,系统核心保证优先级最高的任务运行于CPU.如果有任务优先级高于当前的任务优先级,系统立刻保存当前任务的上下文,切换

到优先级高的上下文.

[size=-1]Priority Preemption

抢占(Preemptive): 抢占是指当系统处于核心态运行时, 允许任务的重新调度。换句话说就是指正在执行的任务可以被打断,让另一个任务运行。抢占提高了应用对异步事件的响应性能力。操作系统内核可抢占,并不是说任务调度在任何时候都可以发生。例如当一个任务正在通过一个系统调用访问共享数据时,重新调度和中断都被禁止.

任务上下文(Task Context): 任务上下文是指任务运行的环境。例如,针对x86的CPU,任务上下文可包括程序计数器、堆栈指针、通用寄存器的内容.

上下文切换(Context Switching): 多任务系统中,上下文切换是指CPU的控制权由运行任务转移到另外一个就绪任务时所发生的事件,当前运行任务转为就绪(或者挂起、删除)状态,另一个被选定的就绪任务成为当前任务。上下文切换包括保存当前任务的运行环境,恢复将要运行任务的运行环境。上下文的内容依赖于具体的CPU.

轮转调度(Round-Robin Scheduling):使所有相同优先级,状态为ready的任务公平分享

CPU(分配一定的时间间隔,使个任务轮流享有CPU). [size=-1]Round-Robin

Scheduling

系统由256个优先级,从0到255,0为最高,255为最低. 任务在被创建时设定了优先级.也可用

taskPrioritySet ( ) 来改变任务优先级.

任务的主要状态: READY,PEND,DELAY,SUSPEND...

ready-------->pended -----------semTake( )/msgQReceive( )-其他任务 ready-------->delayed-----------taskDelay( )

ready-------->suspended---------taskSuspend( )

pended------->ready-------------semaGive( )/msgQSend( )-其他任务

pended------->suspended---------taskSuspend( ) delayed------>ready-------------expired delay

delayed------>suspended---------taskSuspend( )

suspended---->ready-------------taskResume( )/taskActivate( ) suspended---->pended------------taskResume( )

suspended---->delayed-----------taskResume( )

轮转调度 (Round-Robin): 轮转调度可以扩充到优先抢占方式中,当多个任务优先级相同的情况下,轮转调度算法使任务按平等的时间片运行于CPU,共享CPU.避免一个任务长时间占用CPU,而导致其他任务不能运行.可以用 kernelTimeSlice( ) 来定义时间长度.

taskLock

注意: 一个任务可以调用taskDelete ( ) 删除另一个任务,但是如果一个当前正在运行的任务被删除后,该任务的内存没有释放,而其他任务不知道,依然在等待,结果导致系统stop.用 taskSafe ( ) 和 taskUnsafe ( ) 来保证正在运行的任务不被删除.

用法如下: taskSafe ();

semTake (semId, WAIT_FOREVER); /* Block until semaphore available */ . . . . critical region.

semGive (semId); semGive (semId); /* Release semaphore */ taskUnsafe ();

?

任务间的同步和进程间协调

信号量作为任务间同步和互斥的机制。在 wind 核中有几种类型的信号量,它们分别针对不同的应用需求:二进制信号量、计数信号量、互斥信号量和 POSIX 信号量。所有的这些信号量是快速和高效的,它们除了被应用在开发设计过程中外,还被广泛地应用在VxWorks 高层应用系统中。对于进程间通信,wind 核也提供了诸如消息队列、管道、套接字和信号等机制。

任务间的同步和进程间协调的几种方式:

?

o 内存共享(Shared Memory),对简单的数据共享而言. o 信号量(Semaphore),基本的互斥和同步.

o 消息队列(Message queues)和管道(Pipe),单个CPU中,任务间的信息传递. o 套结字(Socket)和远程调用(Remote procedure calls),相对于网络任务间的通信.

o 信号(Signals),出错处理(Exception handling).

内存共享(Shared Memory)

任务间通信最通常的方式是通过共享的数据结构进行通信,因为所有VxWorks的任务存在于一个单一的线性地址空间,任务间共享数据。全局变量、线性队列、环形队列、链表、指针都可被运行在不同上下文的代码所指向。

[size=-1]Shared Data Structures

互斥(Mutual Exclusion)

互斥是用来控制多任务对共享数据进行串行访问的同步机制。在多任务应用中,当两个或多个任务同时访问共享数据时,可能会造成数据破坏。互斥使它们串行地访问数据,从而达到保护数据的目的. 解决互斥的几种方法:

1. 关闭中断的方法(intLock): 能解决任务和中断ISR之间产生的互斥.

funcA (){ int lock = intLock();. . critical region that cannot be interrupted .intUnlock (lock); }但在实时系统中采取这个办法会影响系统对外部中断

及时响应和处理的能力.

2. 关闭系统优先级(taskLock): 关闭系统优先级,这样在当前任务执行时,除了中断外,不会有其他优先级高的任务来抢占CPU,影响当前程序运行. funcA ()

{ taskLock ();

. . critical region that cannot be interrupted. taskUnlock (); }

这种方法阻止了高优先级的任务抢先运行,在实时系统中也是不适合的,除非关闭优先级的时间特别短.

?

信号量(Semaphore):信号量是解决互斥和同步协调进程最好的方法

VxWorks

信号量提供最快速的任务间通信机制,它主要用于解决任务间的互斥和同步。针对不同类型的问题,有以下三种信号量: ?

二进制信号量(binary) 使用最快捷、最广泛,主要用于同步或互斥; ?

互斥信号量(mutual exclusion) 特殊的二进制信号量,主要用于优先级继承、安全删除和回溯; ?

计数器信号量(counting) 和二进制信号量类似,保持信号量被释放(gaven)的次数 ,主要

用于保护一个资源的多个例程(multiple instances of a resource) 信号量控制,函数介绍:

semBCreate( ) 分配并初始化一个二进制信号量 semMCreate( ) 分配并初始化一个互斥信号量 semCCreate( ) 分配并初始化一个计数信号量 semDelete( ) 终止一个自由的信号量 emTake( ) 占有一个信号量 semGive( ) 释放一个信号量

semFlush( ) 解锁所有等待信号量的任务

semBCreate( ), semMCreate( ), and semCCreate( )返回一个信号量ID作为其它后续任务使用该信号量的的句柄。当一个信号量被创建,它的队列(queue)类型就被确定。等待信号量的任务队列以优先级的高低排列(SEM_Q_PRIORITY),或者一先到先得的方式排列(SEM_Q_FIFO).

当一个Semaphore创建时,指定了任务队列的种类

? semBCreat( SEM_Q_PRIORITY, SEM_FULL), SEM_Q_PRIORITY 指明处于等待状态的任务在等待队列中以优先级的顺序排列

? semBCreat(SEM_Q_FIFO,SEM_FULL), SEM_Q_FIFO指明 处于等待状态的任务在等待队列中以先进先出的顺序排列

? 二进制信号量(binary) ? [size=-1]Taking

a

Semaphore

[size=-1]

Giving

a

Semaphore

互斥进程(Mutual Exclusion) 互斥信号量有效的内锁对共享资源的进入,与屏蔽中断(disabling interrupts)和优先级锁定(preemptive locks)相比,二进制信号量将互斥的范围限制在仅与其有关的资源上。从技术上说,创建一个信号量来保护(guarding)资源。信号量初始化位可用的(FULL)。 当一个Semaphore创建时,指定了这个semaphore

是用在解决互斥还是用来同步任务

semBCreat( SEM_Q_FIFO, SEM_FULL) , SEM_FULL 指明用于任务间互斥. SEM_ID semMutex;

semMutex = semBCreate (SEM_Q_PRIORITY, SEM_FULL);

当一个任务要进入资源,首先要得到一个信号量(take that semaphore),只要有任务在使用这个信号量,其它的要进入资源的任务要停止执行(blocked from execution),当这个任务完成了对资源的使用,它会释放信号量,允许另一个任务来使用资源。 semTake (semMutex, WAIT_FOREVER);

. . critical region, only accessible by a single task at a time . semGive (semMutex);

同步协调进程(Synchronization)

? semBCreat(SEM_Q_FIFO,SEM_EMPTY), SEM_EMPTY 指明用于任务间同步.

/* includes */#include \\syncSem;/* ID of sync semaphore */init ( int someIntNum ){ /* connect interrupt service routine */intConnect (INUM_TO_IVEC (someIntNum), eventInterruptSvcRout, 0);/* create semaphore */syncSem = semBCreate (SEM_Q_FIFO, SEM_EMPTY);/* spawn task used for synchronization. */taskSpawn (\100, 0, 20000, task1, 0,0,0,0,0,0,0,0,0,0);}task1 (void){ ...semTake (syncSem, WAIT_FOREVER);/* wait for event to occur */printf (\1 got the semaphore/n\process event */}eventInterruptSvcRout (void){ ...semGive (syncSem);/* let task 1 process event */...}

semTake(semID,time out)--------有Semaphore空闲,就Take, 如果没有,由time out 定,超时则向下执行

?

互斥信号量

? 互斥信号量是一个特殊的二进制信号量,设计用于优先级继承,安全删除和回归。 互斥信号量的使用基本和二进制信号量是类似的。但有以下不同: 仅仅被用做互斥。

? 只能被使用它的任务释放.(It can be given only by the task that took it.) ? ISR 不能释放它。

? 不能使用函数semFlush( )。

优先级反转(Priority Inversion)

优先级反转是指一个任务等待比它优先级低的任务释放资源而被阻塞,如果这时有中等优先级的就绪任务,阻塞会进一步恶化。优先级继承技术可用来解决优先级反转问题。

time for a lower-priority task to complete.

Priorityinversion arises when a higher-priority task is forced to wait an indefinite period of

优先级继承(Priority Inheritance)

优先级继承可用来解决优先级反转问题。当优先级反转发生时,优先级较低的任务被暂时地提高它的优先级,使得该任务能尽快执行,释放出优先级较高的任务所需要的资源。

[size=-1]Priority Inheritance

The mutual-exclusion semaphore has the option SEM_INVERSION_SAFE, which enables a priority-inheritance algorithm. The priority-inheritance protocol assures that a task that owns a resource executes at the priority of the highest-priority task blocked on that resource. Once the task priority has been elevated, it remains at the higher level until all mutual-exclusion semaphores that the task owns are released; then the task returns to its normal, or standard, priority. Hence, the \any intermediate-priority tasks. This option must be used in conjunction with a priority queue (SEM_Q_PRIORITY).

?

计数信号量(Counting Semaphores)

计数信号量是任务同步和互斥的另一种实现方式.计数信号量除了保留信号量被释放的次数以外和二进制信号量是一样的。每次信号量被释放(gaven)一次,计数增加;每次信号量被占用(taken)一次,计数减少;当计数减少为0时,要求得到信号量的任务被阻塞(blocked)。二进制信号量是如果一个信号量被释放,有一个任务阻塞等待,则这个任务就被unblock.而计数信号量如果一个信号量被释放,没有任务阻塞等待,则计数增加。这说明一个被释放两次的计数信号量可以被占用(taken)两次,没有阻塞。

Counting semaphores are useful for guarding multiple copies of resources. For example, the use of five tape drives might be coordinated using a counting semaphore with an initial count of 5, or a ring buffer with 256 entries might be implemented using a counting semaphore with an initial count of 256. The initial count is specified as an argument to the semCCreate( ) routine.

[size=-1]Counting Semaphore Example

[size=-1]Sema

[size=-1]Coun[size=-1]Resulting Behavior

phore Call

t after Call

semCCreate(

Semaphore initialized with initial count of 3.

) 3

semTake( ) Semaphore taken.

2

semTake( ) Semaphore taken.

1

semTake( ) Semaphore taken.

0

semTake( ) Task blocks waiting for semaphore to be available.

0

semGive( ) Task waiting is given semaphore.

0

semGive( ) No task waiting for semaphore; count incremented.

1

消息队列(Message queues)

现实的实时应用由一系列互相独立又协同工作的任务组成。信号量为任务间同步和联锁提供了高效机制。在VxWorks中,用于但一CPU任务之间通信主要(primary)的机制是消息队列。

[size=-1]Full Duplex Communication Using Message

Queues

消息队列允许一定数量不同长度的消息进行排列。任何任务或中断服务程序(ISR)能够发送消息给消息队列。任何任务可以从消息队列接受消息。多任务可以从同意消息队列发送和接受消息。两个任务之间的全双工(Full-duplex)通信需要针对不同方向的两个消息队列。

消息队列函数介绍

msgQCreate( ) 创建斌初始化一个消息队列 msgQDelete( ) 终止并释放一个消息队列 msgQSend( ) 发送一个消息到消息队列 msgQReceive( ) 从消息队列接受一个消息

消息队列是由函数msgQCreate (MAX_MSGS, MAX_MSG_LEN, MSG_Q_PRIORITY)创建。它的参数MAX_MSGS指定了消息队列中可允许最多可以排列的消息数和每个消息允许的最大的字节数MAX_MSG_LEN。

一个任务或中断服务程序(ISR)用函数msgQSend( )发送一个消息到消息队列。如果没有任务等待消息队列的消息,这个消息被添加消息缓存的队列里。如果某些任务已经在等待消息队列中的消息,消息立刻被传递给第一个等待的消息的任务。

一个任务用函数msgQReceive( )从消息队列得到一个消息。如果消息队列缓存中有消息存在,第一个消息立刻出列并回到调用处(caller).如果没有消息存在,则任务(calling task)停止(blocks)并被添加到等待消息的任务队列中。这个等待的任务队列按照优先级或先进先出(FIFO)规则排列,这个规则有消息队列创建时所指定。 等待时间限制(time out)

msgQSend( ) 和 msgQReceive( )都有时间限制参数。当发送一个消息,如果消息队列缓存这时没有空间,这个参数指定允许等待的时间(ticks数),直到队列缓存有空间来接收消息。当接收消息时,如果消息队列没有消息,这个参数指定允许等待的时间(ticks数),直到消息队列有消息。

/* In this example, task t1 creates the message queue and sends a message * to task t2. Task t2 receives the message from the queue and simply * displays the message. *//* includes */ #include \#include \ /* defines */ #define MAX_MSGS (10) #define MAX_MSG_LEN (100) MSG_Q_ID myMsgQId; task2 (void) { char msgBuf[MAX_MSG_LEN]; /* get message from queue; if necessary wait until msg is available */ if (msgQReceive(myMsgQId, msgBuf, MAX_MSG_LEN, WAIT_FOREVER) == ERROR) return (ERROR); /* display message */ printf (\from task 1:/n%s/n\msgBuf); } #define MESSAGE \from Task 1\task1 (void) { /* create message queue */ if ((myMsgQId =

msgQCreate (MAX_MSGS, MAX_MSG_LEN, MSG_Q_PRIORITY)) == NULL) return (ERROR); /* send a normal priority message, blocking if queue is full */ if (msgQSend (myMsgQId, MESSAGE, sizeof (MESSAGE), WAIT_FOREVER, MSG_PRI_NORMAL) == ERROR) return (ERROR); }

管道(Pipes)

管道对消息队列提供了一个可供选择的接口,VxWorks的I/O系统。管道是虚拟的I/O设备,由驱动pipeDrv管理。函数pipeDevCreate()创建一个管道设备,这个调用指定管道的名字,能被排列的最多的消息数,和每个消息允许的长度。

status = pipeDevCreate (\/pipe/name\max_msgs, max_length);

被创建的管道是一个通常命名(named)的I/O设备,任务能用标准的I/O函数打开,读,写管道,并能调用ioctl例程。当任务试图从一个空的管道中读取数据,或向一个

满的管道中写入数据时,任务被阻塞。和消息队列一样,ISR可以向管道写入,但不能从管道读取。

做为I/O设备,管道提供了消息队列所没有的重要特性,调用select()

( )和 taskUnlock ( ) 用来取消优先抢占方式 和恢复优先抢占方式.

VxWorks编程常用函数说明

VxWorks编程常用函数说明

一、官方的Program Guide

位于安装目录下:/docs/vxworks/guide/index.html

二、常用的库:

#include \任务 */ #include \消息队列 */ #include \信号量 */ #include \

#include \ #include \信息输出 */ #include \网络套接字 */

三、IO系统:ioLib.h

1、系统中的IO设备,包括键盘、串口、文件等,都用统一的接口访问。第一步通常先得到文件描述符,然后进行读写或者设置的工作,最后关闭该描述符。

creat:建立文件

open:得到文件或设备的描述符 read:读文件或设备 write:写文件或设备 ioctl:设置参数 close:关闭文件描述符 remove:删除文件 2、内存文件

memDrv( ) -初始化伪内存设备 memDevCreate( ) -建立伪内存设备

memDevCreateDir( ) -建立一组伪内存设备

memDevDelete( ) -删除伪内存设备 Init() {

uchar_t buffer[1024]; int fd; memDrv( );

memDevCreate(\ if ((fd = open(\ write(fd, &data, sizeof(data)); … … close(fd); }

memDevDelete(\ }

3、通过Select函数实现多个IO监听:selectLib.h

当等待多个IO时,我们可以使用Select函数,fd为文件描述符: int select(

int width, /*最大的fd,或直接FD_SETSIZE (2048) */ fd_set * pReadFds, /*读的fd集合 */ fd_set * pWriteFds, /*写的fd集合 */

fd_set * pExceptFds, /* vxWorks不支持,NULL */

struct timeval * pTimeOut /*等待时间, NULL = forever */ )

还有几个宏:

FD_SET(fd, &fdset)设置fd的监听位 FD_CLR(fd, &fdset)清除fd的监听位 FD_ZERO(&fdset)清除所有监听位 FD_ISSET(fd, &fdset) fd是否有数据 例子,其中MAX意为取最大值: Init() {

struct fd_set readFds; int fds[4]; int width;

fds[0] = open(..);… …;fds[3] = open(..); /*打开IO */ width = MAX(fds[0],… … , fds[3])+1; /* fd的最大值+1 */ /* FOREVER {*/

FD_ZERO(&readFds); /*设置fd_set结构 */

FD_SET(fds[0], & readFds);… …; FD_SET(fds[3], & readFds);

if (select(width, &readFds, NULL, NULL, NULL) == ERROR) { /*监听*/ close(fds[0]);… …; close(fds[3]); return; }

for(i=0; i

if (FD_ISSET(fds[i], &readFds)) { … …; /*进行读写操作 */

} } /* } */ }

四、多任务环境的编程: 1、任务控制:taskLib.h taskSpawn( ) -创建任务

taskInit( ) -初始化任务,用户自己指定栈和PCB地址 taskActivate( ) -激活已经初始化的任务 exit( ) -在任务中结束 (ANSI) taskDelete( ) -删除任务

taskDeleteForce( ) -强制删除,即使被保护 taskSuspend( ) -挂起任务 taskResume( ) -恢复挂起的任务 taskRestart( ) -重新启动任务 taskPrioritySet( ) -改变任务优先级 taskPriorityGet( ) -读取任务优先级 taskLock( ) -禁止任务调度 taskUnlock( ) -允许任务调度 taskSafe( ) -保护任务不被删除 taskUnsafe( ) -解除保护

taskDelay( ) -延时

taskIdSelf( ) -得到当前任务的ID taskIdVerify( ) -任务ID是否存在

taskTcb( ) -得到任务控制块(TCB)的地址 taskOptionsSet( ) -改变任务选项 taskOptionsGet( ) -得到任务当前选项

taskRegsGet( ) -得到任务TCB中寄存器的信息 taskRegsSet( ) -设定任务TCB中寄存器的信息 taskName( ) -得到任务名称 taskNameToId( ) -由名称得到ID taskIdDefault( ) -设置默认的任务ID taskIsReady( ) -任务是否就绪 taskIsSuspended( ) -任务是否挂起 taskIdListGet( ) -得到活动的任务列表 2、任务互斥 -信号量:semLib.h semGive( )– 释放一个信号量

semTake( )– 获取一个信号量,会阻塞

semFlush( )– 使所有阻塞在本信号量上的任务变为就绪状态 semDelete( )– 删除一个信号量 1)二进制信号量:semBCreate

可用于任务同步和互斥,但常用于任务同步 2)互斥信号量:semMCreate

专门用于任务互斥的信号量,保护临界资源 3)计数信号量:semCCreate 多实例资源的访问控制 3、任务同步

1)消息队列:msgQLib.h 消息队列

msgQCreate( ) -创建消息队列 msgQDelete( ) -删除消息队列 msgQSend( ) -发送消息

msgQReceive( ) -接受消息,调用后阻塞 msgQNumMsgs( ) -得到消息队列中的消息数量 Init() {

/*创建消息队列 */

if ((msgQID = msgQCreate(8, 1, MSG_Q_FIFO)) == NULL) { printf(\ } }

taskSend() {

if (OK != msgQSend(msgQID, \printf(\ } }

taskReceive() { uchar_t ch;

msgQReceive(msgQID, &ch, 1, WAIT_FOREVER); /*这里任务会阻塞 */ printf(\ }

2)管道:ioLib.h,系统默认包含了pipe驱动组件 pipeDevCreate( ) -创建管道 pipeDevDelete( ) -删除管道

由于管道属于IO,所以可以使用Select监听,消息队列不是IO,不能使用Select Init() { /*创建管道 */

if (pipeDevCreate(\ printf(\ }

/*创建互斥信号量 */

if ((semMID = semMCreate(SEM_Q_FIFO)) == NULL) {

printf(\ } }

taskSend() {

int pd; /* pipe的描述符 */

if ((pd = open(\ printf(\ }

if (semTake(semMID, NO_WAIT) == ERROR) { printf(\ }

write(pd, \ semGive(semMID); close(pd); }

taskReceive() {

int pd; /* pipe的描述符 */ uchar_t ch;

if ((pd = open(\printf(\ }

if (read(pd, &ch, 1)>0) { /*这里任务会阻塞 */ printf(\ } }

3)二进制信号量

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 )

函数运行成功返回任务ID号,否则为ERROR。 任务可选项的几种模式如下表: 名 称 值 描 述

VX_FP_TASK

VX_NO_STACK_FILL VX_PRIVATE_ENV VX_UNBREAKABLE

VX_SUPERVISOR_MODE 0x8 0x100 0x80 0x2

运行带浮点的协处理器 不使用0xee填充堆栈 用私有环境运行任务 断点失效

用户任务常用值

2.taskDelete 删除一个任务 STATUS taskDelete (

int tid )

删除指定ID号的任务,并释放任务所占有的内存 3.taskDelay 延迟任务 STATUS taskDelay (

int ticks )

任务延迟为某一任务休眠一定时间提供了简单的处理方法,一般用于任务的周期性循环执行。当输入参数为NO_WAIT(其值为零)时,表示将所延迟的任务切换到同一优先级

就绪队列的尾部。

4.taskSuspend 任务悬置 STATUS taskSuspend (

int tid )

5.taskResume 恢复任务 STATUS taskResume (

int tid )

6.msgQCreate 创建并初始化消息队列 #include MSG_Q_ID msgQCreate (

int maxMsgs,

int maxMsgLength, int options )

消息入列方式有两种:MSG_Q_FIFO 先进先出 ,按时间先后顺序考虑;MSG_Q_PRIORITY 按消息优先级考虑。 7.msgQSend 向一消息队列发送消息包 STATUS msgQSend (

MSG_Q_ID msgQId, char * buffer, UINT nBytes, int timeout, int priority )

该函数将长度为nBytes的缓冲区buffer消息包发向消息队列msgQId. 如果任务正在等待接收该消息队列的消息包,消息将立即被送到第一个等待的任务。如果没有任务等待此消息,消息包被保留在消息队列中。

参数timeout指明:当消息队列已满时,等待消息队列有空间时所等待的时间。超过该时间还没空间可用的话,消息包被舍弃。它有两个特殊值:NO_WAIT(0)立即返回,不管消息包是否被发送;WAIT_FOREVER(-1)一直等待消息队列有空间可用。

参数priority指明发送的消息的优先级,可能值有:MSG_PRI_NORMAL(0)正常优先级,将消息置于消息队列的尾部;MSG_PRI_URGENT(1)紧急消息,将消息置于消息队列的首部。

8.msgQReceive 接收消息 int msgQReceive (

MSG_Q_ID msgQId, char * buffer,

UINT maxNBytes, int timeout )

该函数从消息队列msgQId接收消息,将其拷贝到最大长度为maxNBytes的缓冲区buffer。如果消息包长度超过maxNBytes,多余部分被舍弃。等待时间timeout有两个特殊值: NO_WAIT(0)立即返回;WAIT_FOREVER(-1)一直等待消息队列有消息可取。 9.msgQDelete 删除一个消息队列 STATUS msgQDelete (

MSG_Q_ID msgQId )

任何因发送或接收该消息队列的消息的任务都将解阻,并返回错误errno. 10. wdCreate 创建看门狗定时器 WDOG_ID wdCreate(void) 11. wdStart 启动定时器 STATUS wdStart (

WDOG_ID wdId, int delay,

FUNCPTR pRoutine, int parameter )

12. wdCancel 取消一个当前工作的定时器 STATUS wdCancel (

WDOG_ID wdId )

该函数只是让定时器的延迟值为零来取消其工作。 13. wdDelete 删除定时器 STATUS wdDelete (

WDOG_ID wdId )

14. semBCreate 创建并初始化二进制信号量 SEM_ID semBCreate (

int options,

SEM_B_STATE initialState )

信号量初始化状态值有两种:SEM_FULL(1)或SEM_EMPTY(0)。选项参数指明被阻塞任务的入列方式:基于优先级(SEM_Q_PRIORITY)和先进先出(SEM_Q_FIFO). 15. semCCreate 创建并初始化计数信号量 SEM_ID semCCreate (

int options, int initialCount )

选项参数指明被阻塞任务的入列方式:基于优先级(SEM_Q_PRIORITY)和先进先出(SEM_Q_FIFO).

16. semGive 给出信号量 STATUS semGive (

SEM_ID semId )

17. semTake 获得信号量 STATUS semTake (

SEM_ID semId int timeout )

如果任务在规定时间内未得到信号量,函数semTake返回错误。等待时间值WAIT_FOREVER和NO_WAIT分别表示一直等待和不等待。 18. semDelete 删除信号量 STATUS semDelete (

SEM_ID semId )

该函数释放与此信号量相关的资源,所有等待此信号量的任务解阻。 semMCreate( ) 分配并初始化一个互斥信号量 semCCreate( ) 分配并初始化一个计数信号量 semDelete( ) 终止一个自由的信号量 semTake( ) 占有一个信号量 semGive( ) 释放一个信号量

semFlush( ) 解锁所有等待信号量的任务

semBCreate( ), semMCreate( ), and semCCreate( )返回一个信号量ID作为其它后续任务使用该信号量的的句柄。当一个信号量被创建,它的队列(queue)类型就被确定。等待信号量的任务队列以优先级的高低排列(SEM_Q_PRIORITY),或者一先到先得的方式排列(SEM_Q_FIFO). · 当一个Semaphore创建时,指定了任务队列的种类

A. semBCreat( SEM_Q_PRIORITY, SEM_FULL), SEM_Q_PRIORITY 指明处于等待状态的任务在等待队列中以优先级的顺序排列

B. semBCreat(SEM_Q_FIFO,SEM_FULL), SEM_Q_FIFO指明 处于等待状态的任务在等待队列中以先进先出的顺序排列 1. 二进制信号量( binary) Taking a Semaphore

Giving a Semaphore

互斥进程(Mutual Exclusion)

互斥信号量有效的内锁对共享资源的进入,与屏蔽中断(disabling interrupts)和优先级锁定(preemptive locks)相比,二进制信号量将互斥的范围限制在仅与其有关的资源上。从技术上说,创建一个信号量来保护(guarding)资源。信号量初始化位可用的(FULL)。 当一个Semaphore创建时,指定了这个semaphore是用在解决互斥还是用来同步任务 A. semBCreat( SEM_Q_FIFO, SEM_FULL) , SEM_FULL 指明用于任务间互斥. SEM_ID semMutex;

semMutex = semBCreate (SEM_Q_PRIORITY, SEM_FULL);

当一个任务要进入资源,首先要得到一个信号量(take that semaphore),只要有任务在使用这个信号量,其它的要进入资源的任务要停止执行(blocked from execution),当这个任务完成了对资源的使用,它会释放信号量,允许另一个任务来使用资源。 semTake (semMutex, WAIT_FOREVER);

. . critical region, only accessible by a single task at a time . semGive (semMutex);

同步协调进程(Synchronization)

B. semBCreat(SEM_Q_FIFO,SEM_EMPTY), SEM_EMPTY 指明用于任务间同步.

#include \h\ #include \h\ SEM_ID syncSem;

init ( int someIntNum ) {

intConnect (INUM_TO_IVEC (someIntNum), eventInterruptSvcRout, 0);

syncSem = semBCreate (SEM_Q_FIFO, SEM_EMPTY);

taskSpawn (\ }

task1 (void) { ...

semTake (syncSem, WAIT_FOREVER);

printf (\he semaphore/n\ ... }

eventInterruptSvcRout (void) { ...

semGive (syncSem);

... }

semTake(semID,time out)--------有Semaphore空闲,就Take, 如果没有,由time out 定,超时则向下执行

2. 互斥信号量

互斥信号量是一个特殊的二进制信号量,设计用于优先级继承,安全删除和回归。 互斥信号量的使用基本和二进制信号量是类似的。但有以下不同: · 仅仅被用做互斥。 · 只能被使用它的任务释放.(It can be given only by the task that took it.) · ISR 不能释放它。 · 不能使用函数semFlush( )。 优先级反转(Priority Inversion)

优先级反转是指一个任务等待比它优先级低的任务释放资源而被阻塞,如果这时有中等优先级的就绪任务,阻塞会进一步恶化。优先级继承技术可用来解决优先级反转问题。

Priority inversion arises when a higher-priority task is forced to wait an indefinite period of time for a lower-priority task to complete. 优先级继承(Priority Inheritance)

优先级继承可用来解决优先级反转问题。当优先级反转发生时,优先级较低的任务被暂时地提高它的优先级,使得该任务能尽快执行,释放出优先级较高的任务所需要的资源。 Priority Inheritance

The mutual-exclusion semaphore has the option SEM_INVERSION_SAFE, which

enables a priority-inheritance algorithm. The priority-inheritance protocol assures that a task that owns a resource executes at the priority of the highest-priority task blocked on that resource. Once the task priority has been elevated, it remains at the higher level until all mutual-exclusion semaphores that the task owns are released; then the task returns to its normal, or standard, priority. Hence, the \heriting\by any intermediate-priority tasks. This option must be used in conjunction with a priority queue (SEM_Q_PRIORITY).

3. 计数信号量(Counting Semaphores)

计数信号量是任务同步和互斥的另一种实现方式.计数信号量除了保留信号量被释放的次数以外和二进制信号量是一样的。每次信号量被释放(gaven)一次,计数增加;每次信号量被占用(taken)一次,计数减少;当计数减少为0时,要求得到信号量的任务被阻塞(blocked)。二进制信号量是如果一个信号量被释放,有一个任务阻塞等待,则这个任务就被unblock.而计数信号量如果一个信号量被释放,没有任务阻塞等待,则计数增加。这说明一个被释放两次的计数信号量可以被占用(taken)两次,没有阻塞。

Counting semaphores are useful for guarding multiple copies of resources. For example, the use of five tape drives might be coordinated using a counting semaphore with an initial count of 5, or a ring buffer with 256 entries might be implemented using a counting semaphore with an initial count of 256. The initial count is specified as an argument to the

semCCreate( ) routine. Counting Semaphore Example Semaphore Call Count after Call Resulting Behavior semCCreate( ) 3 semTake( ) semTake( ) semTake( ) semTake( ) semGive( ) semGive( ) 2 1 0 0 0 1 Semaphore initialized with initial count of 3. Semaphore taken. Semaphore taken. Semaphore taken. Task blocks waiting for semaphore to be available. Task waiting is given semaphore. No task waiting for semaphore; count incremented. 消息队列(Message queues) 现实的实时应用由一系列互相独立又协同工作的任务组成。信号量为任务间同步和联锁提供了高效机制。在VxWorks中,用于但一CPU任务之间通信主要(primary)的机制是消息队列。 Full Duplex Communication Using Message Queues 消息队列允许一定数量不同长度的消息进行排列。任何任务或中断服务程序(ISR)能够发送消息给消息队列。任何任务可以从消息队列接受消息。多任务可以从同意消息队列发送和接受消息。两个任务之间的全双工(Full-duplex)通信需要针对不同方向的两个消息队列。 消息队列函数介绍 msgQCreate( ) 创建斌初始化一个消息队列 msgQDelete( ) 终止并释放一个消息队列 msgQSend( ) 发送一个消息到消息队列 msgQReceive( ) 从消息队列接受一个消息 消息队列是由函数msgQCreate (MAX_MSGS, MAX_MSG_LEN, MSG_Q_PRIORITY)创建。它的参数MAX_MSGS指定了消息队列中可允许最多可以排列的消息数和每个消息允许的最大的字节数MAX_MSG_LEN。 一个任务或中断服务程序(ISR)用函数msgQSend( )发送一个消息到消息队列。如果没有任务等待消息队列的消息,这个消息被添加消息缓存的队列里。如果某些任务已经在等待消息队列中的消息,消息立刻被传递给第一个等待的消息的任务。 一个任务用函数msgQReceive( )从消息队列得到一个消息。如果消息队列缓存中有消息存在,第一个消息立刻出列并回到调用处(caller).如果没有消息存在,则任务(calling task)停止(blocks)并被添加到等待消息的任务队列中。这个等待的任务队列按照优先级或先进先出(FIFO)规则排列,这个规则有消息队列创建时所指定。 等待时间限制(time out)

msgQSend( ) 和 msgQReceive( )都有时间限制参数。当发送一个消息,如果消息队列缓存这时没有空间,这个参数指定允许等待的时间(ticks数),直到队列缓存有空间来接收消息。当接收消息时,如果消息队列没有消息,这个参数指定允许等待的时间(ticks数),直到消息队列有消息。

#include \h\ #include \msgQLib.h\

#define MAX_MSGS (10)

#define MAX_MSG_LEN (100)

MSG_Q_ID myMsgQId;

task2 (void) {

char msgBuf[MAX_MSG_LEN];

if (msgQReceive(myMsgQId, msgBuf, MAX_MSG_LEN, WAIT_FOREVER) == ERROR)

return (ERROR);

printf (\ }

#define MESSAGE \ task1 (void) {

if ((myMsgQId = msgQCreate (MAX_MSGS, MAX_MSG_LEN, MSG_Q_PRIORITY)) == NULL)

return (ERROR);

if (msgQSend (myMsgQId, MESSAGE, sizeof (MESSAGE), WAIT_FOREVER, MSG_PRI_NORMAL) == ERROR) return (ERROR); }

管道(Pipes)

管道对消息队列提供了一个可供选择的接口,VxWorks的I/O系统。管道是虚拟的I/O设备,由驱动pipeDrv管理。函数pipeDevCreate()创建一个管道设备,这个调用指定管道的名字,能被排列的最多的消息数,和每个消息允许的长度。

status= pipeDevCreate (\/pipe/name\max_msgs, max_length);

被创建的管道是一个通常命名(named)的I/O设备,任务能用标准的I/O函数打开,读,写管道,并能调用ioctl例程。当任务试图从一个空的管道中读取数据,或向一个满的管道中写入数据时,任务被阻塞。和消息队列一样,ISR可以向管道写入,但不能从管道读取。 做为I/O设备,管道提供了消息队列所没有的重要特性,调用select()

本文来源:https://www.bwwdw.com/article/gu9w.html

Top