首页 理论教育 嵌入式系统任务通信与同步

嵌入式系统任务通信与同步

时间:2023-11-23 理论教育 版权反馈
【摘要】:任务之间这种制约性的合作运行机制称为任务间的同步。系统中任务的同步是依靠任务与任务之间互相发送消息来保证同步的。该函数功能是从等待任务队列中删除HPT 任务,并将该任务置于就绪态。③OSEventTaskWait()函数,用于使一个任务进入等待某事件发生的状态。使用信号量进行任务之间同步信号量是一类事件,使用信号量的最初目的,是共享资源设立一个表示该共享资源被占用情况的标志。使用信号量可以在任务间传递信息,实现任务的同步执行。

嵌入式系统任务通信与同步

嵌入式系统中的各个任务都是以并发的方式来运行的,并为同一个大的任务服务,它们不可避免地要共同使用一些共享资源,并且在处理一些需要多个任务共同协作来完成的工作时,还需要相互的支持和限制。 因此,对于一个完善的多任务操作系统来说,系统必须具备完备的同步和通信机制,任务间的同步指异步环境下的一组并发出执行任务因各自的执行结果互为对方的执行条件,因而任务之间需互发信号,以使得各任务按一定的速度执行。

在多任务合作工作中,OS 应该解决两个问题:①各任务间应该具有一种互斥关系,即对于某个共享资源,如果一个任务正在使用,则其他任务只能等待,等到该任务释放该资源后,等待的任务之一才能使用它,例如共享打印机。 ②相关的任务在执行上要有先后次序、一个任务要等其伙伴发来通知,或建立了某个条件后才能继续执行,否则只能等待。 例如:A 向buff 中读数据,B 向buff 中写数据,只有在B 写数据才能让A 读数据。

任务之间这种制约性的合作运行机制称为任务间的同步。 系统中任务的同步是依靠任务与任务之间互相发送消息来保证同步的。

任务间的同步依赖任务间的通信,在μC/OS-Ⅱ中,使用信号量、邮箱(消息邮箱)和消息队列这些被作为时间的中间环节来实现任务之间的通信。 μC/OS-Ⅱ中将信号量、消息邮箱和消息队列这类用于任务同步和通信的数据结构称作事件,μC/OS-Ⅱ中,任务或中断服务子程序可以通过事件控制块ECB(Event Control Blocks)向另外的任务发信号。 这里的信号被看成事件,如信号量、邮箱、消息队列等。

(1)事件控制块ECB

事件控制块ECB 是用于实现信号量管理、邮箱管理、消息队列管理等的基本数据结构。其结构如下:

(2)事件控制块的操作

对于事件控制块进行的操作包括以下几种:

①OSEventWaitListInit()函数,用于初始化一个事件控制块。 当建立一个信号量、邮箱或者消息队列时,需要初始化事件控制块中的等待任务列表,这是通过调用OSEventWaitListInit()完成的。 该函数初始化一个空的等待任务列表,列表中没有任何任务。

②OSEventTaskRdy()函数,用于使一个任务进入就绪态。 当所等待的事件发生时,需要将该事件等待任务列表中的最高优先级任务HPT(Highest Priority Task)置于就绪态,该操作是由该事件对应的发送事件(信号量、邮箱、消息队列)函数调用OSEventTaskRdy()实现的。该函数功能是从等待任务队列中删除HPT 任务,并将该任务置于就绪态。

③OSEventTaskWait()函数,用于使一个任务进入等待某事件发生的状态。 当某个任务要等待某一个事件的发生时,需要将当前任务从就绪任务表中删除,并放到相应事件的事件控制块的等待任务表中,此操作是由相应的等待事件(信号量、邮箱、消息队列)函数调用OSEventTaskWait()函数实现的。

④OSEventTO()函数,用于由于等待超时而将任务置为就绪态状态。 当在预先指定的时间内任务等待的事件没有发生时,OSTimeTick()函数会因为等待超时而将任务的状态置为就绪。 此项工作是由发送事件(信号量、邮箱、消息队列)函数调用OSEventTO()完成的。 该函数负责从事件控制块中的等待任务列表里将任务删除,并将它置成就绪状态,最后从任务控制块中将指向事件控制块的指针删除。 应当注意的是,调用OSEventTO()时应当先关中断。

(3)使用信号量进行任务之间同步

信号量是一类事件,使用信号量的最初目的,是共享资源设立一个表示该共享资源被占用情况的标志。 这样,就可使任务在访问共享资源之前,先对这个标志进行查询,在了解资源被占用的情况之后,再决定自己的行为。

使用信号量可以在任务间传递信息,实现任务的同步执行。 μC/OS-Ⅱ中的信号量由两部分组成:一个是信号量的计数值,它是一个16 位的无符号整数(0 ~65 535);另一个是由等待该信号量的任务组成的等待任务表。 使用信号量实现同步主要使用如下函数:

①OSSemCreate()函数,用于建立信号量,并对信号量赋0 ~65 535 的一个数为其初值。如果该信号量是用来表示有n 个相同的资源可访问,则该初始值设为n,即n 代表可访问的资源数,并将该信号量作为一个可计数的信号量使用。 如果信号量是表示发生的事件个数,则该信号量的初始值应设为“0”。 如果信号量是用于表示对共享资源的访问,那么该信号量的初始值应设为“1”(例如,将它当作二值信号量使用)。

②OSSemDel()函数,用于删除一个信号量。 注意:在删除一个信号量之前,必须首先删除操作该信号量的所有任务。

③OSSemPend()函数,用于等待一个信号量,对信号量进行减“1”操作。 当信号量当前是可用(信号量的计数值大于“0”)时,函数将“无错”代码返回给它的调用函数。 如果信号量的计数值小于等于“0”,而OSSemPend()函数又不是由中断服务子程序调用的,则调用OSSem-Pend()函数的任务要进入睡眠状态,等待另一个任务(或者中断服务子程序)发出该信号量。

④OSSemPost()函数,用于发送一个信号量,对信号量进行加“1”操作。 若加“1”后的信号量等于“0”,则OSSemPost()函数还需要唤醒一个处于等待该信号的其他任务。

⑤OSSemAccept()函数,用于无等待地请求一个信号量,功能是当一个任务请求一个信号量时,如果该信号量暂时无效,让该任务简单地返回,而不是进入睡眠等待状态。

⑥OSSemQuery()函数,用于查询一个信号量的当前状态,用户随时可以调用函数OSSemQuery()来查询一个信号量的当前状态。

下面的代码使用信号量实现了两个任务之间的同步。 信号量创建的代码如下,信号量Sem2 初始为可用状态,而信号量Sem1 初始为不可用状态。

Sem1 =OSSemCreate(0);

Sem2 =OSSemCreate(1);(www.xing528.com)

任务Task1 必须等待Sem2 可用才能够继续往下运行,而Sem2 在Task2 中发送。 同样Task2 必须等待Sem1 可用才能够继续往下运行,而Sem1 在Task1 中发送,这样就实现了下面“…”之间代码的顺序执行,而不受TimeDlv 的延时值的影响。

(4)使用消息邮箱实现任务之间的通信

在多任务操作系统中,常常需要在任务与任务之间通过传递数据(这种数据称为“消息”)的方式来进行通信,为了达到这个目的,可以在内存中创建一个存储空间作为该数据的缓冲区。 如果将这个缓冲区称为消息缓存区,在任务间传递数据(消息)的一个最简单的方法就是传递消息缓冲区指针。 因此,用来传递消息缓冲区指针的数据结构就称为消息邮箱。

使用邮箱通信就是由发送消息的任务申请与接收消息的任务建立一个链接的邮箱,发送消息的任务将一个指针型的变量送往邮箱,接收进程从邮箱中取出该指针变量,从而完成进程间信息交换。 该指针指向一个包含了“消息”的特定数据结构。 具体可通过如下函数实现:

①OSMboxCreate()函数,用来创建邮箱,并指定其初始值。 一般情况下,这个初始值是NULL,但也可以初始化一个邮箱,使其在最开始就包含一条消息。 如果使用邮箱的目的是通知一个事件的发生(发送一条消息),那么就要初始化该邮箱为NULL,因为在开始时,事件可能还没有发生。 如果用户用邮箱来共享某些资源,那么就要初始化该邮箱为一个非NULL 的指针。 在这种情况下,邮箱被当成一个二值信号量使用。 使用邮箱同样可以实现上节描述的任务间的同步。

②OSMboxDel()函数,用于删除一个邮箱。 注意:在删除邮箱之前,必须首先删除可能操作该邮箱的所有任务。

③OSMboxPost()函数,用来向邮箱发送一则消息。 这时,如果邮箱中已经有消息,则返回“邮箱已满”的错误代码。 同时该函数还要检查是否有任务在等待该邮箱中的消息,若有还需唤醒该任务。

④OSMboxPend()函数,用于等待发送一个消息到邮箱中,如果邮箱中没有可用的消息,调用OSMboxPend()的任务就被挂起,直到邮箱中有了消息或者等待超时。

⑤OSMboxPostOpt()函数,用于向邮箱发送一则消息。 该函数是μC/OS-Ⅱ的新增函数,可以代替OSMboxPost()函数。 此外,该函数可以向等待邮箱的所有任务发送消息,即广播。

⑥OSMboxAccept()函数,用于无等待地从邮箱中得到一个消息,功能是当邮箱为空时,应用程序也可以无等待的方式从邮箱中得到消息,不必使该任务进入睡眠状态。 注意:调用OSMboxAccept()的函数必须检查其返回值。 如果返回值是NULL,说明邮箱是空的,没有可用的消息;如果返回值是非NULL 值,说明邮箱中有消息可用,而且该调用函数已经得到了该消息。

⑦OSMboxQuery()函数,用于随时查询一个邮箱的当前状态。

(5)使用消息队列实现任务之间的通信

上面说到的消息邮箱不仅可用来传递一个消息,而且也可定义一个指针数组。 让数组的每个元素都存放一个消息缓冲区指针,任务就可以通过传递这个指针数组指针的方法传递多个消息了,这样可以传递多个消息的数据结构就称为消息队列(简称“队列”)。

消息队列是μC/OS-Ⅱ的另一种通信机制,它可以使一个任务或者中断服务子程序向另一个任务发送以指针方式定义的变量。 对于不同的应用,每个指针指向的数据结构也不同。

μC/OS-Ⅱ提供了以下七个对消息队列进行操作的函数:

①OSQCreate()函数:创建消息队列函数;

②OSQPend()函数:等待消息队列函数;

③OSQPost()函数:先进先出(FIFO)发送消息函数;

④OSQPostFront()函数:后进先出(LIFO)发送消息函数;

⑤OSQAccept()函数:无等待获取消息函数;

⑥OSQFlush()函数:清空消息队列函数;

⑦OSQQuery()函数:查询消息队列函数。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈