《操作系统原理》学习笔记,多进程和多线程的优缺点?IPC进程间通信的方式?

操作系统原理

1.处理器

每个处理器都有自己的指令系统(指令集),处理器的物理组成如下:

  • 运算器:实现任何指令的算数和逻辑运算,是计算机计算的核心。
  • 控制器:负责控制程序运行的流程,包括取指令,维护CPU的运行状态,CPU与内存的交互。
  • 寄存器:是指令在CPU内部运算过程中存放数据、内存地址以及指令信息的存储设备,在计算机存储系统中具有最快的存储速度。
  • 高速缓存:处于CPU和物理内存之间,用户多级存储结构,均衡CPU和内存的速度,一般由控制器中的内存管理单元(MMU)管理。

2.寄存器

寄存器(register)为CPU本身提供了一定的存储能力,分为:

  • 用户可见寄存器:可由用户使用。
  • 控制和状态寄存器:用于控制处理器操作,一般由管态下的操作系统代码使用。

根据作用进行分类:

  • 数据寄存器:也称通用寄存器,主要用于各种算数逻辑指令和访存指令
  • 地址寄存器:用于存放数据/指令的物理地址、线性地址或有效地址,用于特定的某种方式的寻址,如索引、段指针、栈指针等
  • 条件码寄存器:保存CPU操作结果的各种标记位,如算数运算产生的溢出、符号等。这些标记在条件分支指令中被测试,以控制程序指令的流向
  • 程序计数器(Program Counter,PC):记录了将要取出的指令的物理地址
  • 指令寄存器(Instruction Register,IR):包含最近取出的指令
  • 程序状态码(Program Status Word,PSW):它记录了CPU运行模式信息,用以表明CPU当前的工作状态,通常包括CPU的工作状态码(管态还是目态)、条件码(反应指令执行后的结果特征)、中断屏蔽码(是否允许中断)等

3.指令处理

处理指令的最简单方式包括两个步骤:cpu先从内存中读取一条指令,然后执行,这样单条指令的处理过程称为一个“指令周期”,程序的执行就是由许多指令周期组成。

典型的处理器中,处理器依据在PC中保存的指令地址,从内存中取出一条指令,并在取指令完成后根据指令类别自动将PC的值改为下一条指令,指令存放在指令寄存器,CPU将解释执行。

  • 访问内存指令:负责CPU和内存之间的数据传输
  • I/O指令:负责CPU和I/O模块之间的数据传送和命令发送
  • 算数逻辑指令:又称数据处理指令,用以执行有关数据的算术和逻辑操作
  • 控制转移指令:这种指令可以指定一个新的指令执行起点
  • CPU控制指令:用以修改处理器状态、改变CPU工作方式等

特权指令是指在指令系统中那些只能由操作系统使用的指令,多数系统将CPU的工作状分为管态和目态。前者一般指OS管理程序运行的状态,具有较高的特权级别,又称系统态、特权态,后者一般指用户程序运行时的状态,又称普通态、用户态。

CPU状态是动态改变的,状态切换可通过特权指令直接设置PSW。

当在用户态执行特权指令时,CPU将拒绝执行该指令,并形成一个“非法事件”的操作。中断机制识别该事件后,转交给操作系统处理。

4.关于进程

进程是具有一定独立功能的程序,关于某个数据集合上的一次运行活动。进程是系统进行资源分配和调度的一个独立单位,从OS的角度可将进程分为系统进程(执行操作系统程序,完成OS的某些功能)和用户程序运行后的用户进程(优先级低于系统进程)

进程的组成大致如下:

  • 指令(可执行代码)
  • 数据
  • PCB

PCB是一个用于描述进程基本情况,以及进程运行变化过程的数据结构。它是进程存在的唯一标志,当系统创建进程时,为进程设置PCB,再利用PCB对进程进行控制和管理。撤销进程时,系统回收PCB,进程随之消亡。PCB包含的数据内容可分为:

  • 调度信息:供进程调度时使用,描述进程的当前状态,包括进程名、进程号、存储信息、优先级、当前状态、 资源清单、家族关系、消息队列指针、当前打开的文件表等。
  • 现场信息:描述了进程当前的运行情况,由于每个进程都有自己的专属内存工作区,现场信息只记录那些可能会被其它进程改变的寄存器数据(比如程序状态字、时钟、界地址寄存器、程序计数器等)
系统将所有进程的PCB排成若干队列(线性方式、索引方式、链表方式等)

5.关于线程

进程是一个可拥有资源的独立单位,同时又是一个可以独立调度和分派的基本单位。引入线程之后,进程是拥有资源的单位,线程作为运行调度单位。

每个线程拥有一个唯一的标识符和线程描述表,可执行相同程序。同进程中的线程共享该进程的内存存储空间,相互通信无需调用内核,同意进程中,线程切换不会引起进程切换,不同进程中的线程切换将会引起进程切换。

  • 用户级线程:这种线程不依赖于内核,只存在于用户态中,对它的操作不会通过系统调用来实现,内核也不知道它的存在。同时它可以在不支持线程的OS上进行实现(线程的调度由进程内的一个运行时系统进行维护)。
  • 内核级线程:这种线程依赖于内核,在内核中保留了线程控制块和所有线程的线程表,通过系统调用对线程表的更新完成线程的各种操作,线程表中保存了每个线程的寄存器、状态和其它信息(PCB的子集)

6.进程/线程模型

6.1 三状态模型

“三状态进程模型”下的进程分为运行、等待、就绪三种状态:

  • 运行状态:指进程已获得CPU,并且在CPU上执行的状态
  • 就绪状态(Ready):指进程已经具备运行条件,但由于没有获得CPU而不能运行的状态
  • 等待状态(Wait):指进程等待某种事件发生,而暂时不能运行的状态。

6.2 五状态模型

“五状态模型”分为创建、运行、就绪、阻塞、结束五种状态。

IPC,进程间通信

参考:https://ost.51cto.com/posts/3330

进程通信( InterProcess Communication,IPC)就是指进程之间的信息交换。常见的进程通信机制:

  • 管道(也称作共享文件)
  • 消息队列(也称作消息传递)
  • 共享内存(也称作共享存储)
  • 信号量和 PV 操作
  • 信号
  • 套接字(Socket)
    《操作系统原理》学习笔记,多进程和多线程的优缺点?IPC进程间通信的方式?
    IPC进程通信

1.匿名管道

Linux 管道使用竖线 | 连接多个命令,这被称为管道符。

$ command1 | command2 

以上这行代码就组成了一个管道,它的功能是将前一个命令(command1)的输出,作为后一个命令(command2)的输入。管道中的数据只能单向流动,也就是半双工通信,如果想实现相互通信(全双工通信),则需要创建两个管道。

另外,通过管道符 | 创建的管道是匿名管道,用完了就会被自动销毁。并且,匿名管道只能在具有亲缘关系(父子进程)的进程间使用。也就是说,匿名管道只能用于父子进程之间的通信。

在 Linux 的实际编码中,是通过 pipe 函数来创建匿名管道的,若创建成功则返回 0,创建失败就返回 -1:

// 该函数拥有一个存储空间为 2 的文件描述符数组:
// fd[0] 指向管道的读端,fd[1] 指向管道的写端
// fd[1] 的输出是 fd[0] 的输入

int pipe (int fd[2]);

对于管道两端的进程而言,管道就是一个文件(管道也被称为共享文件机制),但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在于内存中。

管道的本质就是内核在内存中开辟了一个缓冲区,这个缓冲区与管道文件相关联,对管道文件的操作,被内核转换成对这块缓冲区的操作。

2.有名管道

匿名管道由于没有名字,只能用于父子进程间的通信。为了克服这个缺点,提出了有名管道,也称做 FIFO,因为数据是先进先出的传输方式。

所谓有名管道也就是提供一个路径名与之关联,这样,即使与创建有名管道的进程不存在亲缘关系的进程,只要可以访问该路径,就能够通过这个有名管道进行相互通信。

# 使用 Linux 命令 mkfifo 来创建有名管道:
$ mkfifo myPipe

# myPipe 就是这个管道的名称,往 myPipe 这个有名管道中写入数据:
$ echo "hello" > myPipe

# 执行这行命令后,程序就阻塞了,因为管道里的内容没有被读取,只有当管道里的数据被读完后,命令才可以正常退出。
执行另外一个命令来读取这个有名管道里的数据
$ cat < myPipe
hello 

3.共享内存

共享内存就是允许不相干的进程将同一段物理内存连接到它们各自的地址空间中,使得这些进程可以访问同一个物理内存,这个物理内存就成为共享内存。如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。

《操作系统原理》学习笔记,多进程和多线程的优缺点?IPC进程间通信的方式?
共享内存

4.Socket

Socket 起源于 Unix,原意是插座,在计算机通信领域,Socket 被翻译为套接字,它是计算机之间进行通信的一种约定或一种方式。通过 Socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。