进程间通信(IPC)+进程加锁解锁
【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=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)+进程加锁解锁的更多相关文章
- Linux 进程与线程四(加锁--解锁)
线程共享进程的内存空间,打开的文件描述符,全局变量. 当有多个线程同事访问一块内存空间或者一个变量.一个文件描述符,如果不加控制,那么可能会出现意想不到的结果. 原子操作 对于我们的高级语言(C语言, ...
- 【windows 操作系统】进程间通信(IPC)简述|无名管道和命名管道 消息队列、信号量、共享存储、Socket、Streams等
一.进程间通信简述 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进 ...
- 守护进程,进程安全,IPC进程间通讯,生产者消费者模型
1.守护进程(了解)2.进程安全(*****) 互斥锁 抢票案例3.IPC进程间通讯 manager queue(*****)4.生产者消费者模型 守护进程 指的也是一个进程,可以守护着另一个进程 一 ...
- 使用redis的比较完美的加锁解锁
使用redis的比较完美的加锁解锁 tags:redis read&write redis加锁和解锁 php 习惯性说一下写这篇文章要说明什么,我们经常用redis进行加锁操作,目的是为了解决 ...
- Android进程间通信IPC
一.IPC的说明 IPC是Inter-Process Communication的缩写,含义为进程间通信或跨进程通信,是指两个进程之间进行数据交换的过程. IPC不是Android独有的,任何一个操作 ...
- 进程间通信IPC -- 管道, 队列
进程间通信--IPC(Inter-Process Communication) 管道 from multiprocessing import Pipecon1,con2 = Pipe()管道是不安全的 ...
- linux的IPC进程通信方式-匿名管道(一)
linux的IPC进程通信-匿名管道 什么是管道 如果你使用过Linux的命令,那么对于管道这个名词你一定不会感觉到陌生,因为我们通常通过符号"|"来使用管道,但是管道的真正定义是 ...
- 【IPC进程间通讯之中的一个】邮槽MailSlot
IPC进程间通信+邮槽MailSlot IPC(Inter-Process Communication.进程间通信). 现代计算机採用虚拟内存机制,为进程提 ...
- 进程间通信IPC之--无名管道(pipe)和有名管道(fifo)(转)
进程间通信IPC之--无名管道(pipe)和有名管道(fifo) 2012-01-17 22:41:20 分类: C/C++ 每个进程各自有不同的用户地址空间,任何一个进 程的全局变量在另一个进程中 ...
随机推荐
- 【电脑使用经验】怎么查看无线网络中电脑的IP地址?
1. 2. 3. 4. 5.
- hdu 4858(简单模拟)
项目管理 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- 在Alfred添加自定义站内搜索
1.Google的站内搜索和渣度的对比,懒得吐槽了 2.在Alfred添加自定义站内搜索步骤 Add Custome Search 把搜索某个关键词的url复制到里面,把url里的关键词替换成{que ...
- json.net(Json.NET - Newtonsoft)利用动态类解析json字符串
将对象转换为字符串很简单,唯一要注意的点就是为了避免循环要在需要的字段上添加jsonignore属性.可以参照这篇博文:http://www.mamicode.com/info-detail-1456 ...
- L1-8 外星人的一天
L1-8 外星人的一天(15 point(s)) 地球上的一天是 24 小时.但地球上还有一些精力和勤奋度都远超一般人的大神级人物,他们的“一天”是以 48 小时为周期运转的,这种人被人们尊称为“外星 ...
- node.js博客GitHub搭建(hexo)
教程参考官网提供的: https://hexo.io/zh-cn/ 教程: https://hexo.io/zh-cn/docs/ 我的node.js环境: hexo博客全程采用markdown进行编 ...
- PHP message: PHP Fatal error: require(): Failed opening required
PHP message: PHP Warning: require(/data/wwwroot/blog.sgfoot.com/bootstrap/autoload.php): failed to o ...
- linux基础学习6
daemon 可以理解成为service 两大类: stand_alone:此 daemon 可以自行单独启动服务,加载到内存后就一直占用内存与系统资源:如 www的httpd ,ftp的vsft ...
- android的多次点击事件的实现(有源码)
三次点击事件的原理图:数组的复制(android源码的调用): 下面就是第一步: 创建long数组,里面的数字代表点击的次数. 下面是主要代码实现: system.arraycopy();里面的参数描 ...
- 【java】TreeMap/HashMap的循环迭代中 keySet和entrySet和forEach方式 + map的几种迭代方式
参考链接:https://www.cnblogs.com/crazyacking/p/5573528.html ================================== java紫色代表迭 ...