进程间切换与进程间通讯

591 阅读4分钟

cpu的工作方式

大家用电脑的经验,电脑能同时干好多事。一边听音乐一边写掘金同时还在下载东西,期间还从硬盘拷贝了个电影到电脑。电脑的强大的来源于cpu,但是cpu并不是一个长着三头六臂的怪物,之所以能“同时”干好多事,是因为它速度快。cpu也是一件事一件事干的,每个任务“照顾”一会,不断在任务间轮询,直到所有任务结束或中途退出。轮询的速度快到人类的生理所能察觉到的极限。所以我们一直傻傻地认为所有任务都在同时进行。

电影其实是以很快的速度播放图片,但是人类看到的就是动画,这是人类这种生物的生理构造决定的。

进程间切换

进程是cpu加载程序指令在一堆数据上的一次执行,现在的计算机都是按多道程序设计的,所以需要cpu需要在多个进程间来回切换,轮询工作,这就是进程间的切换,cpu的工作方式决定了必须有进程切换。

被cpu“翻牌”的进程,临时占有cpu,cpu处于运行状态。cpu会在“一堆”进程里翻牌,一堆的意思是所有资源都已准备好,万事具备只差cpu,这种万事具备的进程的状态叫就绪态。

正在执行中的进程,发生意外突然终止,比如被cpu翻牌后没多久,拉肚子需要上厕所,cpu是不会等的,直接把该进程踢出窗(床)外,打入阻塞态,翻另一个就绪态的牌子继续。活该,不踢你踢谁,太扫兴了。

好了,我们的进程切换讲完了。

额外提一点,进程切换还挺耗费系统资源的,为了让你更真切地感受到这种“费劲”,我把一次进程切换cpu要做的事都码出来了:

  • 切换页表全局目录

  • 切换内核态堆栈

  • 切换硬件上下文(进程恢复前,必须装入寄存器的数据统称为硬件上下文)

  • ip(instruction pointer):指向当前执行指令的下一条指令

  • bp(base pointer): 用于存放执行中的函数对应的栈帧的栈底地址

  • sp(stack poinger): 用于存放执行中的函数对应的栈帧的栈顶地址

  • cr3:页目录基址寄存器,保存页目录表的物理地址 ......

  • 刷新TLB

  • 系统调度器的代码执行

进程间通讯方式

进程是相互独立的,每个有自己的独立存储空间,进程间数据不互通不共享。这是程序安全正确执行的必要保障。但是,有些场景就是需要不同进程间相互通信,交换数据。比如微信和妹子聊天的时候,妹子给我们发了一张“美丽的”照片,要完成这个,微信进程肯定要和图片资源管理器进程通信。

为了妹,为了爱,不能通信就创造条件也要通信。当然通信的基础依然是不破坏进程各自独立这个大前提。今天介绍三个方法:共享存储区、消息传递、管道通信。

别急,一个一个把玩。

共享存储区

两个进程要通讯,在进程地盘之外,开辟一个共有的内存空间,进程A可以写可以读,进程B也可以写可以读。

有条件,进程A写的时候,进程B不能读不能写,靠边站,别进来。反过来也是,进程B读的时候,进程A滚开,别写别读。这叫存储区的互斥原则。

消息传递

还是进程A、进程B,各自地盘谁也不能碰。有事?有事发消息呀。系统给每个进程分配了一个存消息的空间,一个队列(当然有大小限制),系统也提供了发消息、收消息方法,基础设施很完善,有想法就发消息吧。

一个消息格式一把包括两部分,消息头和消息体,有点像http请求的报文。

管道通信

除了消息基础设施之外,再来一个基础设施,管道,其实就是一个共享文件,pipe文件,是系统开辟的一块特殊的缓冲空间,系统提供了管道创建和销毁的一系列方法,基础设施嘛。

当然,使用管道,有条件。进程A写的时候,进程B不能读不能写。进程A写了还不行,得把管道写满了,进程B才能读。反过来也是,进程B读的时候,进程A靠边站。得进程B把管道读完了,进程A才能再写。也是互斥的。有个坑就是,数据从管道读出去管道里就没了,不可复读,一次性的。

再额外说一点,管道分有名的和无名的,无名管道一般用于有父子关系的进程间通信。

好了,别再往下翻了,没有了。