【0】README


【1】看看,我们的进程代码

【2】看看IPC替换系统调用 get_ticks 后的调用过程

(本图片是对 source insight 工具打开的系统调用所涉及函数的截图,图片过大,建议使用 在“在新标签页中打开图片”)



对上面两张图的分析(Analysis):(上图中的缓冲区 or 消息发送队列,进程间通信可能用到,也可能用不到)

  • A1)要知道 进程A -> get_ticks -> send_recv -> msg_send or msg_receive 等;
  • A2)系统进程 task_sys 率先启动,调用send_recv(RECEIVE, ANY, &msg)即msg_receive 等待接收消息 ,由于没有任何进程发送消息给它,该进程阻塞;我们看看阻塞代码:

  • A3) 进程A启动,发送消息给 task_sys,进入 系统调用msg_send,关键代码如下:

    if ((p_dest->p_flags & RECEIVING) && /* dest is waiting for the msg */

         (p_dest->p_recvfrom == proc2pid(sender) ||
    p_dest->p_recvfrom == ANY)) {
    assert(p_dest->p_msg);
    assert(m);
    phys_copy(va2la(dest, p_dest->p_msg),
    va2la(proc2pid(sender), m),
    sizeof(MESSAGE));
    p_dest->p_msg = 0;
    p_dest->p_flags &= ~RECEIVING; /* dest has received the msg */
    p_dest->p_recvfrom = NO_TASK;

    unblock(p_dest)

    显然,msg_send 里面的if 语句,系统进程的结构体成员是满足的,所以 进程A向系统进程 task_sys 发送消息成功,(也就是吧进程A的 消息结构体 内容 copy 到 系统进程task_sys 的消息结构体存储空间,由函数 phys_copy 完成)

  • A4)消息发送成功后,返回0, send_recv 函数立即调用 ret = sendrec(RECEIVE, src_dest, msg) 即msg_receive 系统调用 接收 系统进程task_sys 发来的消息;因为 send_recv 中的 src_dest 是指定好了的, src_dest = task_sys(只不过,它传入的参数是task_sys 进程的 进程表 索引)

  • A5)系统进程 task_sys 收到消息后,向先前的 消息发送者(进程A) 发送消息,该消息封装了 ticks 的value值;
  • A6)系统进程 task_sys 调用 msg_send 系统调用,关键代码如下:

    if ((p_dest->p_flags & RECEIVING) && /* dest is waiting for the msg */

         (p_dest->p_recvfrom == proc2pid(sender) ||
    p_dest->p_recvfrom == ANY)) {
    assert(p_dest->p_msg);
    assert(m);
    phys_copy(va2la(dest, p_dest->p_msg),
    va2la(proc2pid(sender), m),
    sizeof(MESSAGE));
    p_dest->p_msg = 0;
    p_dest->p_flags &= ~RECEIVING; /* dest has received the msg */
    p_dest->p_recvfrom = NO_TASK;

    unblock(p_dest)

    显然,msg_send 里面的if 语句,进程A 的结构体成员是满足的,所以 系统进程task_sys 向 进程 A 发送消息成功;

  • A7)进程A 收到消息,抽取出 RETVAL, 关键代码如下:

        send_recv(BOTH, TASK_SYS, &msg);TASK_SYS=1
    return msg.RETVAL;


【3】我们看看 assert (panic类似)怎么调用的?



对sys_printx函数的分析(Analysis):

  • A1)当sys_printx 发现传入字符串的第一个字符是MAG_CH_ASSERT时,会同时判断调用 系统调用的进程是系统进程还是用户进程(通过 sys_printx函数中if 语句 的 p_proc_ready < &proc_table[NR_TASKS]) 判断);
  • A2)如果是系统进程,则停止整个系统的运转,并将要打印的字符串打印在显存的各处;
  • A3)如果是用户进程, 则打印后像一个普通进程一样返回,届时该用户进程会因为 assertion_failure() 中对 函数spin 的调用而进 死循环;
  • Attention):换句话说, 系统进程的 assert 失败会导致系统停止运转(hlt), 而用户进程的失败仅仅导致 自己停转(spin)

【4】我们接着看 进程的加锁 + 解锁

以下有5副图片,第一幅图片是重中之重,给出了 加锁和解锁函数的定义,以及进程切换函数 schedule, 建议在分析的时候,把后4副图片和 第1 副图片做对照,效果更好。



4.1)进程加锁 在何时发生?(block)(这里p->p_flags 置!0 是关键)

  • case1)在msg_send 函数中: 如果消息接收者 没有 指定 该消息发送者,或者接收者没有准备好接收消息,则消息发送者会添加到 接收者的消息发送队列中;【 在本例中,消息发送者是进程A, 它是用户进程,所以进程A被阻塞(spin 死循环函数)】

  • 阻塞(加锁)过程解析:由于 sender->p_flags |= SENDING(参见上图代码),显然 sender->p_flags 不等于零,不会进入assert 函数,直接进入 schedule()进行进程切换,显然 schedule 将CPU控制权切换到那些 p_flags == 0 的进程手里面;也即是只要p->p_flags !=0 ,那么该进程p 就永远也无法进行进程切换,获得CPU控制权(此谓阻塞)

  • 我们这里再添加p_flags 的作用,p_flags 用于表明进程的状态,取值3种(下文不再叙述有关 p_flags 的作用):

    • 1)value = 0:表明进程正在运行或准备运行;
    • 2)value = SENDING(宏定义,具体你不管,反正 !0): 表明进程处于发送消息状态,由于消息没有被送达(该进程还处于接收者进程的发送队列中), 消息发送者进程被阻塞;
    • 3)value = RECEIVING(宏定义,具体你不管,反正 !0): 表明进程处于接收消息状态,由于没有接收到消息, 消息接收者进程被阻塞;
  • case2) 在msg_receive 函数中: 如果没有任何进程向 当前进程发送消息的话,当前进程会阻塞,直到有进程发送消息给当前进程;【举个荔枝:在本例中,当前进程是个系统进程 task_sys,所以这样的话,整个系统会停止运转;】

  • 阻塞(加锁)过程解析:由于 p_who_wanna_recv->p_flags |= RECEIVING (参见上图代码),显然 p_who_wanna_recv->p_flags 不等于零,不会进入assert 函数,直接进入 schedule()进行进程切换,显然 schedule 将CPU控制权切换到那些 p_flags == 0 的进程手里面;也即是只要p->p_flags !=0 ,那么该进程p 就永远也无法进行进程切换,获得CPU控制权(此谓阻塞)

4.2)进程解锁在何时发生?(unblock)(这里p->p_flags 置0 是关键)

  • case1)在msg_send 函数中:如果处于 RECEIVING 状态的进程 接收到了消息,则 就会对该进程进行解锁;判断p->p_flags==0,【举个荔枝:在本例中,消息接收者进程是个系统进程 task_sys,所以这样的话,整个系统会停止运转】;

  • 解锁过程解析:由于 p_dest->p_flags &= ~RECEIVING; /* dest has received the msg */(参见上图代码),显然 p_dest->p_flags ==0,(0==0 -> TRUE)也不会进入assert 函数;紫薇曾经问过:你还记得大明湖畔的夏雨荷吗?我也来问一句:你还记得 加锁过程中调用的 schedule 吗? schedule 函数 阻塞该进程的法宝就是 当其 p_flags非零时,就不会对该进程进行CPU控制权的转让,因为if 语句根本就不满足;现在好了, 在解锁前 p_dest->p_flags &= ~RECEIVING(因为接收到消息前,p_flags==RECEIVING,当然和~RECEIVE 进行逻辑与后 得到0) ;也即是 原先阻塞的进程的p_flags==0 了,它就可以获得CPU控制权了(转向到schedule),这也就解锁了,Bingo!(此谓解锁)

  • case2)在msg_receive 函数中:如果接收者进程 接收任一消息,就从其发送队列中取出一个发送进程,然后发送进程解锁;

  • 解锁过程解析:由于 p_from->p_flags &= ~SENDING(参见上图代码),显然 p_dest->p_flags ==0,(0==0 -> TRUE)也不会进入assert 函数;

    紫薇曾经问过:你还记得大明湖畔的夏雨荷吗?我也来问一句:你还记得 加锁过程中调用的 schedule 吗? schedule 函数 阻塞该进程的法宝就是 当其 p_flags非零时,就不会对该进程进行CPU控制权的转让,因为if 语句根本就不满足;现在好了, 在解锁前 p_dest->p_flags &= ~SENDING(因为接收到消息前,p_flags==SENDING,当然和~SENDING进行逻辑与后 得到0) ;也即是 原先阻塞的进程的p_flags==0 了,它就可以获得CPU控制权(转向到schedule),这也就解锁了,Bingo!(此谓解锁)

版权声明:本文为博主原创文章,未经博主允许不得转载。

进程间通信(IPC)+进程加锁解锁的更多相关文章

  1. Linux 进程与线程四(加锁--解锁)

    线程共享进程的内存空间,打开的文件描述符,全局变量. 当有多个线程同事访问一块内存空间或者一个变量.一个文件描述符,如果不加控制,那么可能会出现意想不到的结果. 原子操作 对于我们的高级语言(C语言, ...

  2. 【windows 操作系统】进程间通信(IPC)简述|无名管道和命名管道 消息队列、信号量、共享存储、Socket、Streams等

    一.进程间通信简述 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进 ...

  3. 守护进程,进程安全,IPC进程间通讯,生产者消费者模型

    1.守护进程(了解)2.进程安全(*****) 互斥锁 抢票案例3.IPC进程间通讯 manager queue(*****)4.生产者消费者模型 守护进程 指的也是一个进程,可以守护着另一个进程 一 ...

  4. 使用redis的比较完美的加锁解锁

    使用redis的比较完美的加锁解锁 tags:redis read&write redis加锁和解锁 php 习惯性说一下写这篇文章要说明什么,我们经常用redis进行加锁操作,目的是为了解决 ...

  5. Android进程间通信IPC

    一.IPC的说明 IPC是Inter-Process Communication的缩写,含义为进程间通信或跨进程通信,是指两个进程之间进行数据交换的过程. IPC不是Android独有的,任何一个操作 ...

  6. 进程间通信IPC -- 管道, 队列

    进程间通信--IPC(Inter-Process Communication) 管道 from multiprocessing import Pipecon1,con2 = Pipe()管道是不安全的 ...

  7. linux的IPC进程通信方式-匿名管道(一)

    linux的IPC进程通信-匿名管道 什么是管道 如果你使用过Linux的命令,那么对于管道这个名词你一定不会感觉到陌生,因为我们通常通过符号"|"来使用管道,但是管道的真正定义是 ...

  8. 【IPC进程间通讯之中的一个】邮槽MailSlot

    IPC进程间通信+邮槽MailSlot                IPC(Inter-Process Communication.进程间通信).        现代计算机採用虚拟内存机制,为进程提 ...

  9. 进程间通信IPC之--无名管道(pipe)和有名管道(fifo)(转)

     进程间通信IPC之--无名管道(pipe)和有名管道(fifo) 2012-01-17 22:41:20 分类: C/C++ 每个进程各自有不同的用户地址空间,任何一个进 程的全局变量在另一个进程中 ...

随机推荐

  1. 基于Xen实现一种domain0和domainU的应用层数据交互高效机制 - 2

    继续昨天的思路,今天先google了类似的实现domain0和domainU之间数据传输的方案 [Xen-devel] XenStore as a data transfer path?  这篇帖子讨 ...

  2. 524. Longest Word in Dictionary through Deleting

    Given a string and a string dictionary, find the longest string in the dictionary that can be formed ...

  3. Codeforces 785D Anton and School - 2(推公式+乘法原理+组合数学)

    题目链接 Anton and School - 2 对于序列中的任意一个单括号对(), 左括号左边(不含本身)有a个左括号,右括号右边(不含本身有)b个右括号. 那么答案就为 但是这样枚举左右的()的 ...

  4. Azure CDN 服务详解

    Azure CDN概述   Azure CDN(内容分发网络)是一种用于分发高带宽内容的全球CDN解决方案,它可以托管在Azure中,也可以通过在任何其他位置,借助Azure CDN,可以托管到任何其 ...

  5. mac与linux服务器之间使用ssh互通有无

    1. 在mac上没有找到好用的shell图形界面的软件,但也是有办法的,使用ssh公钥达到互相有无目的 2.场景是mac连A(linux,以下简称A)服务器 3.登陆mac shell ,按comma ...

  6. iOS 5的文件存储策略应对

    苹果在iOS 5系统时,对app的文件存储提出了新的要求.从它的guildline来看,是推荐开发者尽量把app生成的文件放在Caches目录下的.原文如下: Only user-generated ...

  7. JS: document.getElementBy(), setInerval()

    ylbtech-JavaScript-DOM document.getElementBy(),setInerval() 1.A,document.getElementBy()返回顶部 document ...

  8. GLSL 基础量定义 【转】

    转载:http://blog.csdn.net/misol/article/details/7658949   GLSL语法跟C语言非常相似: 1.数据类型: GLSL包含下面几种简单的数据类型 fl ...

  9. c语言单链表实现

    /************************************************************************* > File Name: singleLin ...

  10. 聚合数据Android SDK 12306火车票查询订票演示示例

    1.聚合SDK是聚合数据平台,为移动开发者提供的免费数据接口.使用前请先到聚合平台(http://www.juhe.cn/)注册,申请相关数据. 2.下载聚合数据SDK,将开发包里的juhe_sdk_ ...