【0】README

  • 0.1) source code and text description are from orange’s implemention of a os;
  • 0.2) for complete code , please visit https://github.com/pacosonTang/Orange-s-OS/tree/master/ipc_8

【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=1return 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. 漫谈QNX(架构/进程,线程,同步,进程间通信IPC)

    (1)架构 说起Blackberry的QNX操作系统, 想必大家都听说过,但到底为什么QNX能如此有名?难道微软的Windows和Linux都不能与之抗衡? 美国NASA的太空接驳飞船也使用QNX操作 ...

  2. Linux进程+进程间通信IPC

    一 Linux进程 1) 进程的内存映像 2)解释 BSS段:在采用段式内存管理的架构中,BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域.BSS是英文Bloc ...

  3. linux进程间通信 ipc,进程间通信IPC (InterProcess Communication)

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

  4. 进程间通信 IPC、LPC、RPC

    原文请见:进程间通信IPC.LPC.RPC 进程间通信(IPC,Inter-Process Communication),指至少两个进程或线程间传送数据或信号的一些技术或方法.进程是计算机系统分配资源 ...

  5. 详解操作系统之进程间通信 IPC (InterProcess Communication)

    进程间通信(IPC,Inter-Process Communication),指至少两个进程或线程间传送数据或信号的一些技术或方法. 进程是计算机系统分配资源的最小单位(严格说来是线程).每个进程都有 ...

  6. Android中进程间通信(IPC)方式总结

    IPC为进程间通信或跨进程通信,是指两个进程进行进程间通信的过程.在PC和移动设备上一个进程指的是一个程序或者一个应用,所以我们可以将进程间通信简单理解为不同应用之间的通信,当然这种说法并不严谨. 在 ...

  7. linux:进程间通信 IPC

    文章目录 1.管道 1.1.匿名管道 1.2.有名管道 2.信号 3.共享内存 3.1.共享内存接口 3.1.1.生成 key 值 3.1.2.创建共享内存 3.1.3.创建共享内存映射 3.1.4. ...

  8. Linux系统编程学习笔记(九)进程间通信IPC

    进程间通信IPC: 我们以前介绍过进程控制原语,看到怎么创建多个进程.但是进程之间交互信息的方式只介绍了通过fork或者exec继承父进程的打开文件或者通过文件系统. 经典的进程通信方式有:管道.FI ...

  9. 进程间通信IPC、LPC、RPC

    IPC是进程间通信,有两种,它们是LPC和RPC,前者是本地过程调用 后者是远程过程调用 简介 进程间通信(IPC,Inter-Process Communication),指至少两个进程或线程间传送 ...

最新文章

  1. css position属性
  2. CSS中的超链接和超链接分类
  3. [20150601]模拟ora-00600[2608]错误.txt
  4. SharePoint Online 创建用户和组
  5. 牛客网暑期ACM多校训练营(第二场)J farm (二维树状数组)
  6. 配置MySQL以进行ADF开发
  7. python groupby填充缺失值_熊猫中的Groupby,用[]填充缺失的组
  8. is present but cannot be translated into a null value due to being declared as a primitive type
  9. [转]网店博客营销之微博实战技巧:还没有做微博的掌柜看过来
  10. Red5服务器端报错:无法解析类型ResourcePatternResolver
  11. linux系统下的打印机驱动下载,foo2zjs linux环境下打印机驱动源代码 - 下载 - 搜珍网...
  12. 物联网ARM开发高级
  13. 智能聊天机器人平台的架构与应用
  14. diy 扫地机器人 滚刷_滚刷结构及扫地机的制作原理
  15. Docker一键部署MySQL
  16. 后端框架flask学习小记
  17. 嵌入式设备NFS挂载目录(基于iTop 4412)
  18. 路由器端口映射,远程桌面连接--端口映射+花生壳=让人访问你个人服务器或WEB站点...
  19. 武侠末世(真香游戏V2.0)
  20. 山东省中小企业数字化转型论坛成功举办,九州云赋能中小企业数智升级

热门文章

  1. 约会安排 HDU - 4553
  2. 牛客题霸 [判断回文] C++题解/答案
  3. CF1534F:Falling Sand(tarjan、贪心、dp)
  4. 不止代码:洛谷P1064 金明的预算方案+P2014选课(依赖背包)
  5. P1337-[JSOI2004]平衡点/吊打XXX【模拟退火】
  6. jzoj6805-NOIP2020.9.26模拟speike【扫描线】
  7. P2717-寒假作业【逆序对,树状数组】
  8. 【2018.5.19】模拟赛之四-ssl2435 航空公司【并查集,二分】
  9. 邓公数据结构C++语言版学习笔记1
  10. 【主席树】可持久化数组(金牌导航 可持久化数据结构-3)