查看: 2250|回复: 0

【连载】嵌入式OS入门笔记-以RTX为案例(八):RTX的进程间通讯(二)

[复制链接]
  • TA的每日心情
    慵懒
    2014-8-14 15:38
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2014-8-16 01:42:42 | 显示全部楼层 |阅读模式
    分享到:
    RTX的进程间通讯主要依赖于四种机制,分别是事件(Event互斥锁(Mutex旗语信号量(Semaphore,和邮箱(Mailbox。前三种机制侧重进程间的同步,邮箱则侧重进程间的数据通讯。上一篇讲了事件和互斥锁。这次讲一下信号量和邮箱。

    1.信号量(Semaphore

    1.简介

        信号量其实是一个很抽象的操作系统原语,它最早由荷兰计算机科学家Dijkstra提 出,用于解决多项资源的分配问题。实际上信号量的适用范围非常广,可以很好地解决很多问题。简单说来,信号量有三个部分,第一部分就是一个代币容器(一个 整形变量),记录着可用的资源数,第二部分就是取用资源(P或者proberen,尝试的荷兰语)的操作,第三个就是还回资源(V或者verhogen, 增加的荷兰语)的操作。当资源数量为0时,任何取用资源的操作都会被阻断,直到资源数量增加。刚刚接触可能会觉得跟互斥锁有点难区分,因为RTX中信号量 的相关操作跟互斥锁基本一致。先看看怎么使用RTX中的信号量。

    类似互斥锁,首先要声明一个信号量结构体。

    OS_SEM semID;然后需要初始化。

    os_sem_init (semID,unsignedtoken_count);

        这里与互斥锁不同的是,你需要指定初始的资源数,token_count,可以是任意非负整数,如果是0,就意味着一开始没有资源可用。

        然后当你需要取用资源时:

    os_sen_wait (semID, timeout );

        timeout的意义就不具体多说了,跟前面介绍的一致。如果成功取用了资源(token_count大于0),那么token_count会减一,并且返回OS_R_OK。如果token_count为0,那么就没办法取用资源,那么这个函数会返回OS_R_SEM,并且进程进入WAIT_SEM状态。

    当你用完了资源,需要返回资源时,(token_count增加1):

    os_sem_send (semID);

        和互斥锁不同的是,当前进程不需要拥有资源,也可以调用该服务,去增加资源数!

    该服务的中断版本:

    isr_sem_set (semID);

    2.信号量和互斥锁的区别

        一般的误区是,信号量用于管理多个只能独享的资源。我们重新考虑上一次提到的场景:整栋房子只有一个公共厕所(共享资源),要使用厕所就要去前台拿钥匙(互斥锁),用完厕所后需要还钥匙给前台。在这种情况下,使用互斥锁机制肯定没问题,那么使用信号量机制会有问题么?

        如果所有人(进程)都循规蹈矩,那没问题。但如果有人没有去厕所,但也还了一把钥匙给前台,那会发生什么事?那就会有两把钥匙,通向同一个厕所,如果当前有 人在上厕所,另外一个人也想要上,前台也会给钥匙给第二个人,那么就会发生尴尬的情况。这个在使用信号量时是有可能的,因为当前进程不需要拥有资源,就能 够os_sem_send!所以哪怕在这种最简单的情况下,也是很有可能误用信号量的。

        复杂一点的情况,我们考虑如果有两个公共厕所,如果使用互斥锁,那就要声明并初始化两个互斥锁,分别管理两个厕所。那么使用信号量机制,初始化一个os_sem_init (toilet,2);的信号量会不会有问题呢?如果我们不考虑有人恶意还钥匙(os_sem_send误用)的话,好像没问题,因为信号量本身就是为了这样的场景(管理多个独享资源)而设计的?

        实际上,一样是会有问题的,因为信号量实际上是不区分资源的,而且也不会记录资源使用的顺序。按照我们的例子,也就是说前台会有两把相同的钥匙,任一一把都 可以打开两个厕所。假设第一个人去前台拿了一把钥匙,进了厕所A,然后第二个人去前台拿了第二把钥匙,实际上第二个人是无法得知,两个厕所里面有没有人, 如果有,是哪一个厕所里面有人。所以,也很有可能会发生尴尬的情况。

        总的来说,当多个独享资源的先后顺序无关时(例如,生产者和消费者问题),使用信号量才比较合适。

        或者当进程本身同时是资源的占用者和释放者时,使用互斥锁:

          OS_MUTmutex;    os_mut_init(mutex);    ...    /*Task 1 */    os_mut_wait(mutex,0xFFFF);    // Critical Section    os_mut_release(mutex);    ...    /*Task 2 */    os_mut_wait(mutex,0xFFFF);    // Critical Section    os_mut_release(mutex);    ...
    当资源的释放者不一定是进程的占用者时,使用信号量:
          OS_SEMsempahore;    os_sem_init(semaphore,0);    ...    /*Task 1 - Producer */    os_sem_wait(semaphore,0xFFFF); // Send the signal    ...    /*Task 2 - Consumer */    os_sem_send(semaphore); // Wait for signal    ...
    3.几个例子

    信号量的用法实在是太丰富,而且很容易误用,具体可以参见《The Little Book of Semaphores》和RTX的官方文档,这里摘几个经典的用法(修改过)作为例子:

      os_semsemaphore;__taskvoid task1 (void) {os_sem_init (semaphore, 0);while (1) {Function1();os_sem_send (semaphore);}}__taskvoid task2 (void) {while (1) {os_sem_wait (semaphore, 0xFFFF);Function2();}}
    这个用法是用于保证不同函数的调用顺序(这是C语言很缺乏的一个特征),在这个例子里面,信号量的作用就是确保在每一次调用Function2之前,Function1都有一次完整的调用。
    Rendezvous
    os_semArrived1, Arrived2;__taskvoid task1 (void) {    os_sem_init (Arrived1, 0);    os_sem_init (Arrived2, 0);    while (1) {        FunctionA1 ();        os_sem_send (Arrived1);        os_sem_wait (Arrived2, 0xFFFF);        FunctionA2 ();    }}__taskvoid task2 (void) {    while (1) {        FunctionB1 ();        os_sem_send (Arrived2);        os_sem_wait (Arrived1, 0xFFFF);        FunctionB2 ();    }}这个用法是更通用的Signaling用法,目的是让FunctionA1,functionB1都完成以后,再执行FunctionA2和FunctionB2。
    os_semMultiplex;__taskvoid task(void){os_sem_init (Multiplex, 5);while (1) {os_sem_wait (Multiplex, 0xFFFF);Function ();os_sem_send (Multiplex);}}
    这个用法能保证最多只有五个进程能够同时调用Function();
    更多的例子,请参考上面提到的材料。
    2.邮箱(Mailbox
    1.简介
    邮箱在RTX中往往是用于在进程间传输大段数据。简单说来,一个邮箱就是一个用户定义长度的队列。队列的每一个单元都是4bytes长,一个单元可以直接保 存数据(32位),或者保存一个指针(地址),指向另外一段数据。用邮箱的一个问题就是要用户手动分配内存和回收内存。下面先看看有哪些相关操作。
    首先要创建一个邮箱,
    os_mbx_declare(mailbox_name,mail_slots)
    在RTL.h中有这个的定义,具体是:
    #define os_mbx_declare(name,cnt) U32name [4 + cnt]
    也就是说邮箱其实是一个名字为mailbox_name,长度为mail_slots的U32数组。另外注意到,额外的4个slots,是用于管理邮箱的,而不是用来直接存储信息的。
    创建完邮箱后就要初始化这个邮箱:
    os_mbx_init (&mailbox_name,sizeof(mailbox_name));
    发信:
    os_mbx_send(&mailbox,msg_ptr,timeout)
    这里的msg_ptr实际上是一个指针,指向需要发送的信息,如果邮箱满了,进程会被阻断,进入WAIT_MBX状态,直到有空间才会返回就绪状态。 timeout的用法和前面的timeout一致。
    同样地,在ISR中有一个相应版本:
    isr_mbx_send(&mailbox,msg_ptr;
    这会先调用isr_mbx_check(),去检查邮箱是否已经满了,如果满了就会放弃当前的信息,并且会被陷入os_error();
    收信:
    os_mbx_wait (&mailbox, &msg_ptr, timeout );
    将收到的信息,存入msg_ptr指向的地址。如果邮箱是空的,进程则会被阻断,进入WAIT_MBX状态,直到有新的信息。
    ISR的相应版本为:
    isr_mbx_receive(&mailbox,&msg_ptr;
    2.BOX内存分配
    在用邮箱的过程中,会经常涉及到RTX的内存分配问题,如果是变长的内存分配,malloc() 和 free()这些标准函数可以胜任,但RTX另外提供了一种处理定长内存块的机制-BOX。
    这里大致简单说一下,具体的用法请参考完整的邮箱例子。
    _declare_box(box_name,block_size,block_count);
    _init_box(box_name,box_size,block_size);
    _alloc_box(box_name);
    _calloc_box(box_name);
    _free_box(box_name,)
    基本上从名字就能知道其意义,和stdlib.h中的标准函数基本对应。
    3.一个完整的例子
    这个例子源于《RL-ARMUser's Guide》,小幅度修改:
    os_mbx_declare(MsgBox, 16); /* Declare an RTX mailbox */U32 mpool[16*(2*sizeof(U32))/4 + 3]; /* Reserve a memory for 16 messages */__task void rec_task (void);__task void send_task (void) {    /* This task will send a message. */    U32 *mptr;    os_tsk_create (rec_task, 0);    os_mbx_init (MsgBox, sizeof(MsgBox));    mptr = _alloc_box (mpool); /* Allocate a memory for the message */    mptr[0] = 0x3215fedc; /* Set the message content. */    mptr[1] = 0x00000015;    os_mbx_send (MsgBox, mptr, 0xffff); /* Send a message to a 'MsgBox' */    os_tsk_delete_self ();}__task void rec_task (void) {    /* This task will receive a message. */    U32 *rptr, rec_val[2];    os_mbx_wait (MsgBox, (void**)&rptr,0xffff); /* Wait for the message to arrive. */    rec_val[0] = rptr[0]; /* Store the content to 'rec_val' */    rec_val[1] = rptr[1];    _free_box (mpool, rptr); /* Release the memory block */    os_tsk_delete_self ();}int main (void) {    _init_box (mpool, sizeof(mpool),sizeof(U32));    os_sys_init(send_task);}
    3.小结

    这一部分是RTX中内容很丰富的一部分,简短的三言两语也许很难概括清楚,这里也只是讲了一些基本的用法。接下来会分析一些并行会遇到的问题。
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-4-28 08:54 , Processed in 0.122403 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.