嵌入式OS入门笔记-以RTX为案例:七.RTX的进程间通讯(一)

来源:互联网 发布:a 算法原理 编辑:程序博客网 时间:2024/05/16 12:51

嵌入式OS入门笔记-以RTX为案例:七.RTX的进程间通讯(一)


上一篇笔记讲了一下RTX的三种调度机制。可以看到RTX配置下是有并发的,也就是有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行的情况。实际上并行是会涉及很多问题的,好比如果只是一个人在干活那么他不需要和别人沟通就能完成这个任务,但如果多人同时在干活(或者是为了同一个目的,或者不是为了同一个目的),如果他们需要共享到一些资源,那就涉及到沟通协调的额外付出了。OS的设计也涉及类似的问题。在进一步讨论一些并发会造成的问题前,我们先介绍一下RTX是如何实现进程与进程间的通讯的。


RTX的进程间通讯主要依赖于四种机制,分别是事件(Event)互斥锁(Mutex)旗语信号量(Semaphore),和邮箱(Mailbox)。前三种机制侧重进程间的同步,邮箱则侧重进程间的数据通讯。这里先讨论事件和互斥锁,信号量和邮箱请参见下一篇。


我们先考虑如下一个场景,A进程运行到一定时间后,需要等待一个外设的信号(或者别的数据),它可以选择忙绿等待(busy-waiting):


...while(something_unfinished){}...

当something_unfinished由真变为假时,A进程才可以跳出这个while循环。此前它一直是在忙等,CPU执行的指令很可能是NOP(一条汇编指令,什么也不做,空转)。所以实际上是浪费CPU资源。这样的做法有些时候是有必要的,但绝大时间,更好的做法是使用类似中断的设计,先让A进程暂停,以执行其他的进程,等到something finishes再来通知A进程。


设计进程间的通讯的一部分功能就是避免忙等,但更多的是为了解决一下并发性问题。下面我们具体看看事件和互斥锁机制。


1.事件(Event)


简单说来,就是每一个进程有16个标示,每个标示只有1和0的状态。进程可以设置其他进程的标示,也就是说通知其他进程,某事件发生了。在满足一定条件的后,就可以激活这个进程。


相应的事件标示保存在TCB(进程控制块)上,如果进程需要等待事件,将会进入WAIT_OR或者WAIT_AND状态,当事件条件满足之后,就会重新进入READY,等待排程器去调度。


具体说来,当进程执行如下几个操作,就会进入等待状态,直到标示状态满足:

os_evt_wait_and(U16wait_flags,U16timeout);

和事件等待,第一个参数是一个十六位的二进制数,哪一位是1就代表进程需要等待那一位的事件标示。第二个参数设置的是最大等待时间,以time tick value为单位,进程只会等待到最大等待事件,然后恢复为就绪状态等待调度。如果设置为0xFFFF,则最大等待时间为无穷,也就是只会等待事件标示状态满足wait_flags的要求。

os_evt_wait_or(U16wait_flags,U16timeout);

与事件等待,参数意义与和事件等待相同。


这两个操作的差别在于(其实应该比较一目了然)对于和事件等待而言,所有标示都满足了,进程才会被唤醒,对于与事件等待而言,任一标示状态满足了就会唤醒进程。 举个例子:

os_evt_wait_and (0xABCD, 0xFFFF);

os_evt_wait_or (0xABCD, 0xFFFF);

第一个语句的话,进程会等待15,13,11,9,8,7,6,3,2,0位(0xABCD)的标示全部被设为1时才会被唤醒,而对第二个语句而言,15,13,11,9,8,7,6,3,2,0位中的任一一位标示被设为1,进程就会被唤醒。


这两个语句返回类型都是OS_RESULT。结果有两种,一是,OS_R_EVT,意思就是事件条件满足了(与或和),进程会被唤醒而且标志会被清零,另外一种就是OS_R_TMO,进程等待超越了最大等待时间。

设置事件标示执行以下操作(一般是别的进程):

os_evt_set(0xABCD,taskID);

这就会设置进程D指定进程的事件标示。

os_evt_clear(0xABCD,taskID);

类似地,这个用于清理进程ID指定进程的事件标示。


另外简单提一下,中断(在RTX中,中断不算进程)也可以设置这些事件标示的,而且RTX提供了一个更加轻量的设置语句:


isr_evt_set (U16 event_flags, OS_TID task_id);

2.互斥锁(Mutex)


如果第一次接触互斥锁,那这个概念其实还不容易解释。总的来说,就是一个锁,他基本的运用就是一个进程需要先取钥匙去解锁(有且只有一把钥匙,且取钥匙和还钥匙的过程不可被中断),完成特定任务后还钥匙以便其他进程可以继续使用。

一个简单的应用场景是,整栋房子只有一个公共厕所(共享资源),要使用厕所就要去前台拿钥匙(互斥锁),用完厕所后需要还钥匙给前台。这样做的原因就是为了保证对某些资源的互斥操作(例如你要避免多个进程同时读写一块内存区域)。一些复杂的话题我们迟点再讨论,先简单说说RTX的互斥锁怎么用。

首先要声明一个互斥锁,互斥锁在RTX中是一个结构体。

OS_MUT mutexID;

然后需要初始化。

os_mut_init (mutexID);

然后当你需要取钥匙(要独占某资源)时:

os_mut_wait (mutexID, timeout );

这个会向RTX申请要独占这个互斥锁,如果没有别的进程占用,那么当前进程就会获得互斥锁,如果有别的进程占用,当前进程就会进入WAIT_MUT状态,直到互斥锁占用被解除,或者timeout,timeout的设置和事件中timeout的设置一样。(0xFFFF为无穷,以timer tick value为单位)。解除后进入就绪状态等待调度。

类似事件,这个也会返回OS_RESULT: OS_R_MUT(互斥锁被其他进程占用),OS_R_TMO(超过最大等待时间),OS_R_OK(成功占用互斥锁)。

要解除互斥锁占用,调用:
os_mut_release (mutexID);

注意,只有占用了互斥锁的进程才能成功解除互斥锁占用!如果进程本身没有占用互斥锁,这个语句不会改变什么。


3.小结


这些只是粗浅地大概记下了一些关于事件和互斥锁的用法。我们以后再讨论另外两种机制的用法,一些具体的例子,和其他更深刻的涉及并发的问题。



1 0
原创粉丝点击