操作系统-进程

虽然通过微机原理对系统的硬件操作有了一定认识,但是对操作系统还是有些一知半解,正好趁着在学习linux,再把操作系统的知识补一补

1. what is 进程

进程的本质:进展中的程序。。即程序+执行

进程出现的起因:多道程序设计

即允许多个程序同时进入内存并运行,目的是为了提高系统效率,进程的出现,让每个用户感觉到自己在独占CPU,但不是并行,而是并发

多道程序技术,使每个程序成为独立的控制流,占用一个逻辑控制器,也就是将一个物理计数器变换成多个逻辑计数器(进程切换),分配给多个程序;

2. 进程模型

2.1 组成

  • 物理层面:cpu只有一个物理的程序计数器(program counter pc),进入指令队列(寄存器)后顺序执行。所以所有进程其实共用一个程序计数器,只是CPU在不停的做进程切换。
  • 逻辑层面:在一个时间范围内,每个进程都可以执行,也可以暂时挂起让别的程序执行,之后又可以接着执行。即每个进程自身也要有逻辑计数器,指向下一条指令。
  • 时间层面:每个进程都必须往前推进

并发环境:一段时间间隔内,单处理器上有两个或两个以上的程序同时处于开始运行但尚未结束的状态,并且次序不是事先确定的。

在并发环境下执行的程序就是并发程序。

2.2 自己的理解

对于单核cpu来说,物理层面上的程序计数器,也就是指针只有一个,指向内存中的命令语句。所以原则上程序只能顺序执行,即一个时刻只有一个进程处于执行状态。但是通过让指针在进程间切换以及给每个进程分配执行时间让cpu在一个时间范围内可以实现多个进程的并发。

对于多核cpu,每个核都是独立的运算处理器,可以实现进程的并行执行

2.3 如何实现

  1. 物理基础
    进程是对程序的抽象,而程序是需要分配内存的。当多个进程并发的时候。需要考虑如何让多个进程共享同一个物理内存而不发生冲突。OS通过内存管理来实现

  2. 进程切换

    所谓进程调度,就是决定什么时候让什么进程来使用cpu

3.进程层次与状态

3.1 层次结构

  • 一个进程在执行过程中可以通过系统调用创建新的进程,这个新的进程就称为子进程,而创建子进程的进程则被称为父进程

  子进程又可以再创建子进程,于是这样子子孙孙地创建下去就形成了所谓的进程树

  • 父进程复制自己的地址空间(fork)创建一个新的子进程结构。每个新进程分配一个,唯一的进程ID(PID),满足跟踪安全性之需,任何进程都可以创建子进程。

​ 所有进程都是第一个系统进程的后代。

3.2 状态转换

  • 基本的进程状态有三种:执行,阻塞和就绪,zombie

    进程被挂起(阻塞)的原因:进程在运行过程中执行了某种阻塞操作,如读写磁盘这种需要等待的操作;或者是一个进程的执行时间太长到点了,轮到别人了。

    R 运行状态(running):并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里
    S 睡眠状态(sleeping):意味着进程在等待事件完成(也可叫做可中断睡眠 interruptible sleep)D 磁盘休眠状态(Disk sleep):有时也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待 I/O的结束
    
    T 停止状态(stopped):可以通过发送SIGSTOP信号给进程来停止(T)进程,这个被暂停的进程可以通过发送SIGCONT信号让进程继续运行
    X 死亡状态(dead):这个状态只是一种返回状态,你不会在任务列表里看到这个状态
    Z 
    

4.进程管理

4.1 方法

与一个社会管理人的过程类似,OS要管理进程就需要维护进程的一些信息,OS用于维护进程记录的结构就是进程表或进程控制块(Process Control Block,PCB)。那么进程表里有什么记录呢?一般来说,维护的记录应该包含:寄存器、程序计数器、状态字、栈指针、优先级、进程ID、创建时间、所耗CPU时间、当前持有的各种句柄等等。

4.2 创建过程(不理解)

分配PCB——初始化机器寄存器——初始化页表——将程序代码从磁盘读进内存——将处理器准状态设为“用户态“——跳转到程序的起始地址(设置程序计数器)

4.3需要解决的问题

公平和效率的权衡

由于无法并行执行,一旦进程发生阻塞挂起(比如执行硬盘读写操作),当前进程无法继续进行,里面有些不同等待读写返回结果的功能也被耽搁了。这是就需要利用线程的概念

5. 进程调度

当多个进程(高并发)同时请求服务器资源的时候,任务的先后顺序无疑是非常重要的,比如玩游戏的时候为什么会提示系统繁忙,稍后再试。。

所以如何高效的利用cpu资源,解决高并发问题无疑是非常关键的。

5.1基础

  1. 目的:选择下一个要执行的进程

  2. 原则:cpu的利用率最大化

    ​ 一般的程序任务分为三种:CPU计算密集型、IO密集型、平衡(计算与IO各半)型,对于不同类型的程序,调度需要达到的目的也有所不同。对于IO密集型,响应时间最重要;对于CPU密集型,则周转时间最重要;而对于平衡型,进行某种响应和周转之间的平衡就显得比较重要。

      因此,进程调度的原则就是要达到极小化平均响应时间、极大化系统吞吐率、保持系统各个功能部件均处于繁忙状态和提供某种貌似公平的机制

  3. 调度过程:

    • 因时序或外部中断或进程挂起导致OS获得CPU控制权

    • OS在所有就绪的进程中按照某种算法遴选进程

    • 如果选中的是当前进程则OS将当前进程状态予以保护
    • 将选中的进程的环境布置好(设置寄存器、栈指针、状态字等)
    • 跳转到选中的进程

5.2 算法(面向服务器思考高并发的处理方法)

  1. 时间片轮转算法

    实现方式:周期性地进行进程切换

    缺点:大锅饭式做法,未考虑短任务情况

  2. 短任务优先算法

    实现方式:增加优先级,即短任务的优先级比长任务高

    两种类型:一种是非抢占式,一种是抢占式。非抢占式当已经在CPU上运行的任务结束或阻塞时,从候选任务中选择执行时间最短的进程来执行。而抢占式则是每增加一个新的进程就需要对所有进程(包括正在CPU上运行的进程)进行检查,谁的时间短就运行谁

    缺点:长任务不能分配到执行时间;进程的剩余时间如何估算

  3. 优先调度算法

    实现方式:同样是增加优先级,但是根据重要性来划分

    缺点:低优先级的任务排队时间长:可以动态调整优先级解决

    ​ 响应时间无法保证:虽然可以将少量任务的优先级设置为最高来保证,但面对多任务还是无法处理

  4. 混合调度算法(扬长避短)

    实现:将所有进程分为不同的大类,每个大类为一个优先级。如果两个进程处于不同的大类,则处于高优先级大类的进程优先执行;如果处于同一个大类,则采用时间片轮转算法来执行。

    优先级1:任务1;任务2;任务3;任务4;任务5;

    优先级2:任务6;任务7;

    优先级3:任务8;任务9;任务10;

5.3优先级倒挂

  1. 概念:优先级倒挂指的是一个低优先级任务持有一个被高优先级任务所需要的共享资源。这样高优先级任务因为资源缺乏而处于受阻状态,一直到低优先级任务释放资源为止。这样实际上造成了这两个任务的优先级倒挂。

  2. 尚不能有效理解,暂时挂起

6.进程通信(沟通方式)

6.1 进程对白(管道,套接字)

像人类说话一样,进程对白就是一个进程发出某种数据信息,另外一方接收数据信息,而这些数据信息通过一片共享的存储空间进行传递

  1. 管道

    说白了就是一个公用存储空间,一个往里写,一个从里拿

    一个进程向存储空间的一端写入信息,另一个进程存储空间的另外一端读取信息,这个就是管道(这里的端只是比喻,数据的读写都是通过总线来进行)

    就像两个人对白的媒介是空气也可以是线缆一样,管道所占的空间既可以是内存也可以是磁盘。

      要创建一个管道,一个进程只需要调用管道创建的系统调用即可,该系统调用所做的事情就是在某种存储介质上划出一片空间,赋给其中一个进程写的权利,另一个进程读的权利即可。

      例如在Linux下,我们通过Shell命令输入两个命令,中间通过符号“|”来创建两个命令之间的管道:

    1
    $ sort < file1 | grep zou

      上面一个命令表示:对file1的内容首先进行排序,排序完成后的结果将作为grep的输入,在结果里面找出所有包括字符串zou的文本行。也就是说,在两个任务“排序“(sort)和”查找”(grep)之间创建了一个管道,数据从sort流向了grep。

  2. 套接字

    套接字(Socket)的功能非常强大,可以支持不同层面、不同应用、跨网络的通信。使用套接字进行通信需要双方均创建一个套接字,其中一方作为服务器方,另外一方作为客户方。服务器方必须首先创建一个服务区套接字,然后在该套接字上进行监听,等待远方的连接请求。客户方也要创建一个套接字,然后向服务器方发送连接请求。服务器套接字在受到连接请求之后,将在服务器方机器上新建一个客户套接字,与远方的客户方套接字形成点到点的通信通道。之后,客户方和服务器方便可以直接通过类似于send和recv的命令在这个创建的套接字管道上进行交流了。

6.2 进程电报与旗语

  1. 电报:信号

    发报文时无需收报人实现知道,也无需进行任何协调。如果对方选择不对信号做出响应,则将被OS终止运行。

  2. 旗语:信号量

    在计算机中,信号量实际上就是一个简单整数。一个进程在信号变为0或1的情况下推进,并将信号变为1或0来防止别的进程同时推进。当该进程完成任务后,则将信号再改为0或1,从而允许其他进程执行。从而我们也可以看出,信号量已经不只是一种通信机制,更是一种同步机制

6.3 进程拥抱

  1. 共享内存

    进程的拥抱就是共享内存,两个进程共同拥有同一片内存。对于这片内存中的任何内容,二者均可以访问。要使用共享内存进行通信,进程A首先需要创建一片内存空间作为通信用,而其他进程B则将片内存映射到自己的(虚拟)地址空间。这样,进程A读写自己地址空间中对应共享内存的区域时,就是在和进程B进行通信。

6.3 进程信件

消息队列:一列具有头和尾的消息排列,新来的消息放在队列尾部,而读取消息则从队列头部开始。

它和管道十分类似,一头读,一头写?的确,看起来很像管道,但又不是管道:

  1. 消息队列无固定的读写进程,任何进程都可以读写;而管道需要指定谁读和谁写;

  2. 消息队列可以同时支持多个进程,多个进程可以读写消息队列;即所谓的多对多,而管道是点对点;

  3. 消息队列只在内存中实现,而管道还可以在磁盘上实现;