【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. LeetCode OJ-- Reorder List **

    https://oj.leetcode.com/problems/reorder-list/ 将一个链表重新排序,比如 1 2 3 4 5,变成 1 5 2 4 3 1.找到中间节点 mid 2.将链 ...

  2. Goodbye 2017 B

    [题意]: 鲍勃编程一个机器人在2d迷宫中导航.迷宫有一些障碍.空单元格用'.'表示,其中障碍物用'#'表示.迷宫中有一个机器人.它的起始位置用字符“S”表示.这个位置没有任何障碍.迷宫中也有一个出口 ...

  3. 2017 ACM-ICPC EC-Final 记录

    北京赛区结束后就以为自己的赛季结束了……但是还是保持着做题量 那天突然接到通知,去打EC-Final 但是这是一个临时组起来的队伍,另外两位队友原来一起组的比较熟,我就需要适应一下. 于是我们临时训练 ...

  4. 安全性测试入门 (四):Session Hijacking 用户会话劫持的攻击和防御

    本篇继续对于安全性测试话题,结合DVWA进行研习. Session Hijacking用户会话劫持 1. Session和Cookies 这篇严格来说是用户会话劫持诸多情况中的一种,通过会话标识规则来 ...

  5. luogu P2423 双塔

    题目描述 2001年9月11日,一场突发的灾难将纽约世界贸易中心大厦夷为平地,Mr. F曾亲眼目睹了这次灾难.为了纪念“911”事件,Mr. F决定自己用水晶来搭建一座双塔.Mr. F有N块水晶,每块 ...

  6. CodeForces - 103D Time to Raid Cowavans

    Discription As you know, the most intelligent beings on the Earth are, of course, cows. This conclus ...

  7. 【Kafka】《Kafka权威指南》——写数据

    不管是把 Kafka 作为消息队列.消息.总线还是数据存储平台来使用 ,总是需要有一个可以往 Kafka 写入数据的生产者和一个可以从 Kafka读取数据的消费者,或者一个兼具两种角 色的应用程序. ...

  8. Mac下ll、l、la、等简写命令不能使用

    Mac默认用的也是Unix系统,Unix系统本身是没有这些简写命令的,可以通过给命令设置别名来使得可以使用这些简写命令 查看本机所有已经设置的命令别名:alias 设置命令别名:alias ll='l ...

  9. 巧用chrome开发者工具

    说明:截图中的Chrome版本为52,不同版本可能略有区别. 常用设置 开发时消除静态资源缓存不能立刻更新的困扰,勾选Disable cache即可 切换颜色显示格式 修改默认颜色显示格式,在Sett ...

  10. html中常用的标签小结

    内容详细标签: <h1>~<h6>标题标签<pre>格式化文本<u>下划线(underline)<i>斜体字(italics)<cit ...