【操作系统-进程】进程间通信:管道

操作系统底层工作的整体认识

在这里插入图片描述
-输入和输出设备:就是我们的磁盘的IO设备(如:键盘,U盘,显示器)
使用这些设备最终反馈的都是电信号,电信号被反馈到内部处理组件里面转成数字信号,所谓的数字信号就是我们的芯片,芯片集成了大量电路,电路通过高低压(高低电阻)判断电信号的开关(1和0),所以这就是我们的CPU为什么只认0101这种二进制的数据。
在这里插入图片描述

CPU

  • 控制单元 :指令计数器、指令寄存器、地址寄存器
  • 运算单元:ALU
  • 数据单元:存储单元(寄存器、CPU缓存):主要存指令、存数据…(要算的时候从内存中捞过来)

在这里插入图片描述
在这里插入图片描述

CPU结构

在这里插入图片描述

  • L3 cache是一个CPU上的多个内核(Core0和Core1)共享.
  • L1和L2是内核独享。
  • 还有一点值得注意:缓存是由最小的存储区块-缓存行(cacheline),缓存行大小通常为64byte
    在这里插入图片描述
    long(8字节)那么一个缓存行只能装64/8=8个long

在这里插入图片描述
先看一个空间局部性原则的例子:
在这里插入图片描述

  • 运行结果是第一种比第二种快
    在这里插入图片描述
  • 第一种是按行加,
    在这里插入图片描述
  • 把二维数组的一维(第一行)读取到cache缓存,只需要跟内存交互一次。
    在这里插入图片描述
    在这里插入图片描述

CPU运行安全等级

在这里插入图片描述

  • CPU在为java程序创建一个线程时(JAT),会从ring3切换到ring0,这里是状态切换

线程模型

  • 内核线程模型(KLT):线程的创建调度和销毁由OS完成
  • 用户线程模型(ULT):线程的创建调度和销毁由用户程序自己完成
    在这里插入图片描述
    在这里插入图片描述
  • 堆栈一般有两个:一个在用户空间,一个在内核空间
  • JVM运用的是KLT线程模型:java启动200个线程时,cpu的线程会立马+200
    在这里插入图片描述
    在这里插入图片描述

线程上下文切换:切换时会把执行结果保存到内存TSS(任务状态段)Task State Segment

在这里插入图片描述

虚拟机指令集架构

在这里插入图片描述

进程

每个进程的用户地址空间都是独立的,一般而言是不能互相访问的,但内核空间是每个进程都共享,所以进程之间要通信必须通过内核。
Linux内核提供了不少进程间通信的机制:

  • 管道
  • 消息队列
  • 共享内存
  • 信号量
  • 信号
  • Socket

管道

linux中的“|”竖线

$ ps auxf| grep mysql

上面命令行里的|竖线就是一个管道,它的功能是将一个命令(ps auxf)的输出,作为后一个命令(grep mysql)的输入,从这功能描述,可以看出管道传输数据是单向的
如果想互相通信,我们需要创建两个管道才行。

同时,|这种管道是没有名字,表示匿名管道,用完了就销毁。

所以相应地,管道还有另外一个类型是命名管道,也叫做FIFO,因为数据是先进先出的传输方式。
在使用命名管道前,先需要通过mkfifo命令来创建,并且指定管道名字:

$ mkfifo myPipe
//myPipe就是管道的名字

基于Linux一切皆文件的理念,所以管道也是文件的方式存在,我们可以用ls查看一下,这个文件的类型是p,也就是pipe(管道)的意思:

$ ls -l
pew-r--r--.
1 root root     0 Aug  11  02:45  myPipe

接下来,我们往myPipe这个管道写入数据:

$ echo "hello" > myPipe    //将数据写进管道
                           //停住了...

你会发现,操作后,就停在这了,这是因为管道里内容没有被读取,只有当管道里的数据被读取后,命令才可以正常退出???
于是我们在另一个终端执行另外一个命令来读取这个管道里的数据:

$ cat   <   myPipe     //读取管道里数据
hello

可以看到,管道里的内容被读取出来了,并打印在了终端上,另外一个方面,echo那个命令也正常退出了。

我们可以看出,管道这种通信方式效率低,不适合进程间频繁地交换数据。当然它的好处自然就是简单哈哈哈。同时我们也很容易得出管道里的数据已经被另外一个进程读取了!!!。完成了进程间的通信!!!

那么,上面讲了命名管道,下面讲讲匿名管道的创建,需要通过下面这个命令调用:

int pipe(int fd[2])

这里表示创建一个匿名管道,并返回了两个描述符,一个是管道的读取端描述符fd[0],另一个是管道的写入端描述符fd[1]。注意,这个匿名管道是特殊文件,只存在内存,不存在文件系统中。
在这里插入图片描述

其实,所谓的管道,就是内核里面的一串缓存
从管道的一端写入数据,实际上是缓存在内核中的,另一端的读取,也就是从内核中读取这段数据。
另外,管道传输的数据是无格式的流且大小受限

但是了解到这,我们不能忘了主题!!!进程间的通信!!!
所以我们这时要会质问:这两个描述符都是在一个进程里面,并没有起到进程间通信的作用,怎么样才能使得管道是跨过两个进程的呢???
我们可以使用fork创建子进程,woc创建的子进程会复制父进程的文件描述符,这样就做到了两个进程各有两个(fd[0]与fd[1]),两个进程就可以通过各自的fd写入和读取同一个管道文件!!!实现跨进程通信了。

但是,管道只能一端读取另一端写入,所以上面这种模式容易造成混乱,因为父进程和子进程都可以同时写入,也可以同时读取。那么为了避免这种情况,通常的做法是:

  • 父进程关闭读取的fd[0],只保留写入的fd[1];
  • 子进程关闭写入的fd[1],只保留读取的fd[0].
    在这里插入图片描述
    所以说如果要双向通信,则应该创建两个管道。
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值