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

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

在这里插入图片描述
-输入和输出设备:就是我们的磁盘的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].
    在这里插入图片描述
    所以说如果要双向通信,则应该创建两个管道。
1. 实验目的 1) 加深对进程概念的理解,明确进程和程序的区别。 2) 进一步认识并发执行的实质。 3) 分析进程争用资源的现象,学习解决进程互斥的方法。 4) 学习解决进程同步的方法。 5) 了解Linux系统中进程通信的基本原理。   进程操作系统中最重要的概念,贯穿始终,也是学习现代操作系统的关键。通过本次实验,要求理解进程的实质和进程管理的机制。在Linux系统下实现进程从创建到终止的全过程,从中体会进程的创建过程、父进程和子进程之间的关系、进程状态的变化、进程之间的互斥、同步机制、进程调度的原理和以管道为代表的进程间的通信方式的实现。 2. 内容及要求:   这是一个设计型实验,要求自行编制程序。   使用系统调用pipe()建立一条管道,两个子进程分别向管道写一句话:   Child process1 is sending a message!   Child process2 is sending a message!   父进程管道读出来自两个子进程的信息,显示在屏幕上。   要求: 1) 父进程先接收子进程1发来的消息,然后再接收子进程2发来的消息。 2) 实现管道的互斥使用,当一个子进程正在对管道进行写操作时,另一子进程必须等待。使用系统调用lockf(fd[1],1,0)实现对管道的加锁操作,用lockf(fd[1],0,0)解除对管道的锁定。 3) 实现父子进程的同步,当子进程把数据写入管道后,便去睡眠等待;当父进程试图从一空管道中读取数据时,也应等待,直到子进程将数据写入管道后,才将其唤醒。 3.相关的系统调用 1) fork() 用于创一个子进程。 格式:int fork(); 返回值:在子进程中返回0;在父进程中返回所创建的子进程的ID值;当返回-1时,创建失败。 2) wait() 常用来控制父进程与子进程的同步。 在父进程中调用wait(),则父进程被阻塞,进入等待队列,等待子进程结束。当子进程结束时,父进程从wait()返回继续执行原来的程序。 返回值:大于0时,为子进程的ID值;等于-1时,调用失败。 3) exit() 是进程结束时最常调用的。 格式:void exit( int status); 其中,status为进程结束状态。 4) pipe() 用于创建一个管道 格式:pipe(int fd); 其中fd是一个由两个数组元素fd[0]和fd[1]组成的整型数组,fd[0]是管道的读端口,用于从管道读出数据,fd[1] 是管道的写端口,用于向管道写入数据。 返回值:0 调用成功;-1 调用失败。 5) sleep() 调用进程睡眠若干时间,之后唤醒。 格式:sleep(int t); 其中t为睡眠时间。 6) lockf() 用于对互斥资源加锁和解锁。在本实验中,该调用的格式为: lockf(fd[1],1,0);/* 表示对管道的写入端口加锁。 lockf(fd[1],0,0);/* 表示对管道的写入端口解锁。 7) write(fd[1],String,Length) 将字符串String的内容写入管道的写入口。 8) read(fd[0],String,Length) 从管道的读入口读出信息放入字符串String中。 4.程序流程 父进程: 1) 创建管道; 2) 创建子进程1; 3) 创建子进程2; 4) 等待从管道中读出子进程1写入的数据,并显示在屏幕上; 5) 等待从管道中读出子进程2写入的数据,并显示在屏幕上; 6) 退出。 子进程: 1) 将管道的写入口加锁; 2) 将信息“Child process n is sending message!”输入到变量OutPipe中,n=1,2; 3) 将OutPipe中信息写入管道; 4) 睡眠等待; 5) 将管道的写入口解锁; 6) 退出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值