乐趣区

关于后端:程序员不得不学的操作系统知识二

过程

过程的组成

过程是操作系统中分配资源的最小单位 。过程由 3 个局部组成,别离是 程序代码 数据集、栈 过程管制块(PCB)

各自的作用如下:

  1. 程序代码:形容了过程须要实现的性能。
  2. 数据集、栈:程序在执行时所须要的数据和工作区。
  3. 过程管制块:蕴含过程的形容信息和管制信息,它是过程存在的惟一标识。
  4. PCB:用来形容和管制过程运行的 通用数据结构,是过程可能独立运行的根本单位。(常驻内存,存在零碎专门凋谢的 PCB 块)

过程的状态

  1. 创立态,调配 PCB 块,插入就绪队列,还未申请其余资源
  2. 就绪态,领有除了 CPU 以外的资源
  3. 运行态,过程取得 CPU 执行权,正在执行
  4. 阻塞态,因为某种原因,位于阻塞状态,放弃 CPU
  5. 终止态,过程完结后由零碎清理并偿还 PCB 块

过程通信

信号 signal:通过向一个或多个过程发送 异步事件信号 来实现,如:SIGSTOP、SIGKILL 等信号。

管道 pipe:在两个过程之间,能够建设一个通道,一个过程向通道写入字节流,另一个过程从管道读取字节流。管道是同步的,当过程尝试从空管道读取数据时,该过程会被阻塞,直到有可用数据为止。如 linux 的 | 管线

共享内存:通过共享内存进行过程间通信,一个过程所作的批改对另一个过程可见。

先入先出队列 FIFO:也称 命名管道,具备反对文件和独特 API,命名管道在文件系统中作为设施的专用文件存在。而非命名管道在完结后缓冲区会被零碎回收。

音讯队列:形容内核寻址空间内的外部链接列表。能够按几种不同的形式将音讯按程序发送到队列并从队列中检索音讯。每个音讯队列由 IPC 标识符惟一标识。

套接字 Socket:提供端到端的双向通信,可有 TCP、UDP 的反对。

进程同步

临界资源 :指的是一些虽作为 共享资源 却又无奈同时被多个过程或线程独特拜访的共享资源。为了对临界资源进行无效的束缚,就提出了 过程间同步的四个准则

  • 闲暇让进:资源无占用,容许应用
  • 忙则期待:资源被占用,申请过程期待
  • 无限期待:保障无限等待时间可能应用资源,防止其它期待的过程僵死
  • 让权期待:期待时,过程需让出 CPU,也就是过程由执行状态变为阻塞状态,这也是保障 CPU 能够高效应用的前提

死锁

死锁定义:如果一组过程中的每个过程都在期待一个事件,而这个事件只能由该组中的另一个过程触发,这种状况会导致死锁

死锁的条件

  1. 互斥条件:资源是排他性应用的
  2. 放弃和期待条件:已领有资源的过程不开释本人的资源,去申请新的资源
  3. 不可抢占条件:过程未应用完的资源不能被其余过程剥夺
  4. 循环期待:死锁产生时,必存在资源环形链路

解决死锁策略

  1. 鸵鸟算法(疏忽死锁带来的影响)
  2. 检测死锁并复原死锁,死锁产生时对其进行检测,一旦产生死锁后,采取行动解决问题(调配时监测是否会产生死锁,能够通过回滚、抢占、杀死过程复原死锁)
  3. 通过正当分配资源来防止死锁(银行家算法,依据闲暇资源表和资源需要表正当分配资源)
  4. 通过毁坏死锁产生的四个条件之一来防止死锁

    • 毁坏互斥条件
    • 毁坏放弃期待条件
    • 毁坏不可抢占条件
    • 毁坏循环期待条件

两阶段加锁

一种解决形式是应用 两阶段提交(two-phase locking)。顾名思义分为两个阶段,一阶段是过程尝试一次锁定它须要的所有记录。如果胜利后,才会开始第二阶段,第二阶段是执行更新并开释锁。第一阶段并不做真正有意义的工作。

如果在第一阶段某个过程所须要的记录曾经被加锁,那么该过程会开释所有锁定的记录并从新开始第一阶段。从某种意义上来说,这种办法相似于事后申请所有必须的资源或者是在进行一些不可逆的操作之前申请所有的资源。

通信死锁

过程 A 给过程 B 发了一条音讯,而后过程 A 阻塞直到过程 B 返回响应。假如申请音讯失落了,那么过程 A 在始终等着回复,过程 B 也会阻塞期待申请音讯到来,这时候就产生 死锁

解决办法:超时重传

** 过程间同步的办法:** 音讯队列、共享存储、信号量。会在后边的文章中具体介绍这些过程间同步的办法

fork 过程

  • fork 零碎调用是用于 创立过程
  • 对于虚拟空间地址来说,子过程会拷贝父过程的虚拟地址空间。所以,fork 后子过程的用户区与父过程的用户区雷同 ,也会 拷贝内核区内容 ,仅仅是 过程的 pid不同。
  • 在父过程中返回子过程的 ID,在子过程中返回 0。所以能够通过fork 的返回值来辨别父过程与子过程
  • fork 零碎调用 无参数

使用了 读时共享、写时拷贝 的准则,fork 后,父子过程共享父过程的地址空间 (只读),在父过程或者子过程进行写指令时,子过程才会复制一份地址空间,从而使得虚拟地址空间独立,在本人的地址空间进行 写操作 。也就是说, 资源的复制是在须要写入时才会进行,在此之前,只会以只读形式进行共享

过程类型

前台过程:具备终端,能够和用户进行交互的过程

后盾过程:不与用户进行交互,优先级比前台过程低

守护过程:非凡的后盾过程

孤儿过程:父过程退出后,子过程即成为孤儿过程,将由 **init 过程(pid 为 1)** 收养

僵尸过程:子过程的过程描述符在子过程退出后不会开释,只有当父过程调用 **wait()、waitpid()** 获取子过程信息才开释

线程

线程是操作系统进行运行调度的最小单位,线程除了领有本人的栈、程序计数器等资源外,共享过程的资源。

通信,对于过程来说是过程间的通信(IPC),而对于线程,它是通过读写同一个过程的数据进行通信。

线程同步

互斥量

  • 实质上是资源排他性应用,成果相当于 原子性 。领有两种状态: 加锁和解锁 。(会带来相干损耗, 阻塞锁

    • 自旋锁 :期待获取资源的时候 CPU 不会开释, 长处 :如果线程占用锁工夫不长,就能防止上下文切换代价; 毛病:消耗 CPU 工夫
    • 读写锁:读不进行加锁,写的时候进行加锁,对于多读少写的状况,性能能有很好的晋升

信号量:示意同时容许拜访资源的最大线程数量,它是一个全局变量。(Java 的 semaphore)

条件变量 :利用线程间共享的全局变量进行同步的一种机制,次要包含两个动作:一个线程期待某个条件为真,而将本人挂起;另一个线程设置条件为真,并告诉期待的线程持续。 条件变量与互斥量一起应用时,容许线程以无竞争的形式期待特定的条件产生。

  • 根本动作:wait、signal、notify

调度算法

  • 调度算法的指标:
  • 先来先服务:依照 FIFO 的准则,将作业退出到就绪队列中,依照程序调度作业。
  • 最短作业优先:依照线程作业的 CPU 工夫片,优先调度所需最短 CPU 工夫片的作业。
  • 最短剩余时间:最短作业优先的抢占式版本,总是调度残余运行工夫最短的作业。
  • 轮询调度:每个作业都会被调配一个 CPU 工夫片,在这个工夫片内容许过程运行。如果工夫片完结时过程还在运行的话,则抢占一个 CPU 并将其调配给另一个过程。
  • 优先级调度:依照作业优先级进行调度。
  • 多级反馈队列:设置多级队列,设置不同优先级,并且调配不同的工夫片。

POSIX 线程

即线程规范。

线程调用 形容
pthread\_create 创立一个新线程
pthread\_exit 完结调用的线程
pthread\_join 期待一个特定的线程退出
pthread\_yield 开释 CPU 来运行另外一个线程
pthread\_attr\_init 创立并初始化一个线程的属性构造
pthread\_attr\_destory 删除一个线程的属性构造

线程实现

在用户空间实现线程

内核并不知道线程的存在,以过程为单位调配 CPU 工夫片,每个过程要有专用的线程表。

长处:容许每个过程有本人定制的调度算法、调度效率比内核调用高(无需陷入内核,即上下文切换,无需刷新内存高速缓存)

毛病:会因为阻塞调用 / 缺页中断阻塞整个过程直到实现

在内核空间实现线程

内核中会有用来记录零碎中所有线程的线程表,当进行系统调度的时候,会通过对线程表的更新进行调度。线程表领有每个线程的寄存器、状态和其余信息。

长处:不会因某个线程阻塞而导致过程阻塞

毛病:零碎调用代价大,上下文切换开销大,以及须要切换零碎状态

混合实现 :将用户级线程与某些或者全副内核线程多路复用起来。编程人员能够自在管制用户线程和内核线程的数量,具备很大的灵便度。 内核只辨认内核级线程,并对其进行调度。其中一些内核级线程会被多个用户级线程多路复用。

理解更多文章,🙋‍♂️关注公众号:学编程的文若

退出移动版