zoukankan      html  css  js  c++  java
  • 理解操作系统2——进程

    进程是计算机操作系统中非常重要的概念。是一种非常重要的抽象。

    ====================================================

    一、为什么要引入进程这个概念?

      先从计算机的体系结构——冯诺依曼体系结构。它是一种将程序指令存储器数据存储器合并在一起的存储器结构。程序指令存储地址和数据存储地址指向同一个存储器的不同物理位置,因此程序指令和数据的宽度相同。这个体系结构有三大原则:采用二进制逻辑、程序存储执行和计算机由五大部分组成。这五大部分是:运算器、存储器、控制器、输入设备、输出设备。

     

    冯诺依曼计算机体系结构理论要点:

      (1)采用存储程序方式,指令和数据不加区别混合存储在同一个存储器中,指令和数据都可以送到运算器进行运算,即由指令组成的程序是可以修改的;
      (2)存储器是按地址访问的线性编址的一维结构,每个单元的位数是固定的;
      (3)指令由操作码和地址组成。操作码指明本指令的操作类型,地址码指明操作数和地址。操作数本身无数据类型的标志,它的数据类型由操作码确定;
      (4)通过执行指令直接发出控制信号控制计算机的操作。指令在存储器中按其执行顺序存放,由指令计数器指明要执行的指令所在的单元地址。指令计数器只有一个,一般按顺序递增,但执行顺序可按运算结果或当时的外界条件而改变;
      (5)以运算器为度中心,I/O设备与存储器间的数据传送都要经过运算器;
      (6)数据以二进制表示。

     这种结构特点是“程序存储,共享数据,顺序执行”,需要 CPU 从存储器取出指令和数据进行相应的计算。

    这种操作系统有以下几个特点:

    (1)单处理机结构,机器以运算器为中心;
    (2)采用程序存储思想;
    (3)指令和数据一样可以参与运算;
    (4) 数据以二进制表示;
    (5)将软件和硬件完全分离;
    (6) 指令由操作码和操作数组成;
    (7)指令顺序执行。 
    这里的存储器包括了:内部存储器(也就是内存)和寄存器。其中寄存器、控制器和运算器共同构成了CPU。这是一个以存储器为核心的计算机体系结构。所以存储交换数据的快慢很大程度上决定了计算机的速度。此外可以发现指令是顺序执行,也就是说处理器是串行执行指令的
     
    这种串行特点在应对多个作业(也叫做程序吧)的时候,就必须把作业一个个做完,一旦其中一个作业是I/O密集型的话,限制作业执行效率的因素就是I/O的读写速度,且大多数时候CPU是空闲的。使得在处理多个作业时,整体效率偏低。为了提高CPU的利用率,那么最好的方式就是让CPU并行地处理这些作业。但是实际上CPU是串行工作的。这该怎么办呢?
     
    这里要谈到两个概念“并行”、“并发”:并行是指同时处理多个任务,并发是指由处理多个任务的能力,但是实际上不一定要同时进行。
    所以只能串行执行任务单核CPU为了看起来像是能够同时执行多个任务,采用了并发的方式同时处理多个任务,看起来像是并行那样。并发技术的实现相当复杂,最容易理解的就是“时间片轮转进程调度”算法。我们这里先理解成有多个任务,所有的任务轮流使用CPU,每个任务占用CPU的时间非常短。使得用户根本感觉不到CPU是在轮流为多个任务提供服务,就好像多个任务在不间断地运行那样。但是实际上在任何一个时间内,只有一个任务占用着CPU。所以这里就是理解并发的关键,它不是并行,因为CPU本质是串行的,只是通过并发技术使得其看起来像并行。
     
    但是并发运行产生了一些问题,
      1、间断性:任务A和任务B根本没啥关系,它们俩是并发执行的,一会儿执行任务A,一会儿执行任务B。
      2、失去封闭性:并发执行的程序,系统中的资源都是共享的,那么任务A执行了的时候改变了资源的状态,在任务B来执行时发现状态改变了,不知它之前想要的状态。这就使得任务A和任务B相互影响。
      3、不可再现性:就是由于程序的运行速度不同,程序的运行环境也有影响,则程序多次执行,虽然它们的初始条件一样,但是运行的结果不一样。因为这个可程序在运行时由于并发,每次运行的环境都不一样,每次运行都是独一无二的。
      以上都是并发的问题,这可怎么办。但是进程的概念的引入很好地解决了上述问题。
    ====================================================
     二、什么是进程
    引入进程的概念是为了使得计算机在多程序环境下并发执行,并且能够对并发执行的程序加以控制,规避上述的问题。
    从不同的角度去看进程,可以得出不同的概念和定义。有时候这些描述把进程这个概念刻画地越来越玄乎,越来越琢磨不透。
    所以一开始我讨论的不是进程是什么,而是为什么要引入进程这个抽象的概念。梳理一下逻辑线条:
    冯诺依曼计算机体系结构--->CPU在执行多任务时效率不高---->采用并发设计克服,提升CPU效率---->并发设计引入新的问题---->引入进程概念解决这些问题
     
    我先解读一下程序的概念,上述表述的任务,在这里也可以解读为程序。
    程序就是一堆指令和数据的集合,程序的目的是让CPU按照顺序读入指令串行地执行下去,去完成特定的任务。
    程序在进入内存之前是存放在磁盘上的,也叫做外存储器。内存是运行存放运行中的程序。程序本身是一个静态的概念
    那么如何描述运行中程序呢?如何在并发时很好地克服上述问题,很好地控制和描述程序的运行?
    需要一个新的概念,这就是——进程进程可以理解为运行中的程序。或者理解成程序动态运行中的实例。
    进程这个抽象概念被创造出来,当然也被计算机赋予了一些重要的意义。
     
    进程是计算机操作系统资源分配的基本单位。进程的概念甚至成为操作系统的基础。
    从物理上来看进程是有程序代码代码相关的数据集以及进程控制块组成的。
    进程是动态的概念,就是运行中的程序。是一个很好地方式去描述运行中的程序。其实引入进程就是体现了封装分治的思想来解决上述并发的问题。让程序之间在轮流使用一个CPU的时候不会相互影响。
     
    进程控制块(PCB)是一个重要的数据结构,操作系统就是通过进程控制块感知进程的存在
     
    进程很好地解决了CPU的利用率问题,使得CPU高效利用

    所有的应用程序以进程的方式运行在比操作系统权限更低的级别。
    每个进程都有自己独立的地址空间;使得进程之间的地址空间相互隔离。
    CPU由操作系统进行统一分配,每个进程根据优先级都有机会得到CPU。具体来讲就是进程的调度方面的知识;
    总体目标是使得每个进程从逻辑上看来都可以独占计算机的资源。
    另外也使得CPU能在多个进程之间很好地共享。

    ====================================================

    三、进程的描述

    既然有了进程这个概念来描述运行中的程序。那么操作系统也必须具备一些手段来管理进程。

    操作系统的作用当然不仅仅要管理进程,还要管理计算机中个其他资源:内存、设备(I/O)、文件等;

    操作系统控制和管理系统资源;操作系统是管理系统资源的实体。
    为处理器执行进程而进行调度和分派,给进程分配资源,响应用户程序的基本服务请求。


    操作系统为了控制进程和管理资源需要哪些信息?

    操作系统管理这些资源和进程的普遍方式就是:创造一个表。构造并维护它所管理的每个实体的信息表。
    一个普遍的方法是操作系统构造并维护它所管理的每个实体的信息表。
    操作系统一般维护着4中不同类型的表:内存、I/O、文件和进程。(操作系统控制表)


    内存表:内存表用于跟踪内存和虚拟内存(外存)。//内存模型和虚拟外存后续文章再介绍。
    内存表用于跟踪内(实)存、外存(虚拟内存)
    内存的某些部分为操作系统而保留,剩余部分是进程可以使用的。
    保存在外存中的进程使用某种类型的虚拟内存或简单的交换机制。
    所以内存表应该包括:
    内存或虚拟内存块的任何保护属性;管理虚拟内存所需要的任何信息;

    I/O表:
    这个表用于管理计算机中系统中的I/O设备和通道。
    操作系统需要知道I/O操作的状态和作为I/O传送的源和目的内存单元。

    文件表:
    提供关于文件是否存在、文件在外存中的位置、当前状态和其他属性的信息。
    大部分信息是由文件管理系统维护和使用的。


    进程表:
    内存、I/O、文件是代表进程而被管理,因此进程表中必须有对于这些资源的直接或间接引用。
    这些表自身也必须可以被操作系统看到,因此它们受制于内存管理。

    操作系统最初是如何创建表?
    很显然需要有一些基本环境的信息。这是一个配置问题。
    当操作系统初始化后,它必须可以使用定义基本环境的某些配置数据,这些数据必须在操作系统之外,
    通过人的帮助或一些自动配置软件产生。

    参考链接:

      进程的组成和描述:https://blog.csdn.net/zpznba/article/details/88399361

     

     

    我们使用进程映像描述一个进程:程序、数据、栈、属性(进程控制块)的集合;

    其实进程就简单分成三个部分(程序、数据、进程控制块)

    进程控制块存放在系统内存中。是进程存在的唯一标识,是操作系统感知进程存在的重要数据结构。

    PCB保存了很多关于进程相关的信息。如下:

    标识符               (就是进程的ID,身份证)
    状态                  (运行、就绪、阻塞等)
    优先级              (决定进程调度)
    程序计数器       (存放下一条指令所在单元的地址的地方,告知CPU下一条指令所在的内存地址)
    内存指针
    上下文数据       (处理机现场信息,方便恢复现场)
    I/O状态信息
    记账信息

     

    进程控制块(PCB):由操作系统创建和管理、是操作系统能够支持多进程和多处理的关键工具。
    当进程被中断后,操作系统会把程序计数器和处理器寄存器(上下文数据)保存到进程控制块中的相应位置。
    进程状态也被改变为其他的值,例如阻塞态或者就绪态。

     

    关于进程控制块的组织形式,这里也有很多内容。暂时不展开讨论

    ====================================================

    四、进程的控制

    要对进行进程控制就必须在操作系统中有专门的结构,进行进程创建、终止、进程通信和资源管理。

    这样的结构被称为:内核(kernel)

    内核的本身不是进程,是硬件的延伸,内核是通过各种原语操作来完成各种控制和管理功能的。

    原语可以认为是机器指令的延伸。由若干条机器指令构成,用以完成特定功能的一段程序。为了保证操作的正确性,原语在执行期间是不可分割的

    用于进程控制的原语有:创建进程、撤销进程、阻塞进程、唤醒进程、调度进程、改变优先级;

     

    这里又联系到进程的优先级,我们来讲讲优先级排列的一些原则:

    1、根据进程的类型:系统进程优先级比用户进程优先级高;

    2、进程所使用的资源量:占用CPU时间越多,优先级越低;

    3、进程在系统中等待时间:等待时间越长,优先级越高;

    等等....

    ====================================================

    五、进程的行为模型

    两状态模型:未运行、运行;
    未运行的进程必须保持在某种类型的队列中。
    因为存在着一些处于非运行状态但已经就绪等待执行的进程,
    而同时存在另外一些处于阻塞状态等待I/O操作结束的进程。
    所以分派器还得考虑队列中那些未被阻塞且在队列中时间最长的进程。


    可以将非运行状态分成两种:阻塞(等待I/O操作完成)和就绪;
    三状态模型:运行、阻塞、就绪;


    新建态、退出态对于进程管理是非常有用的。

    五状态模型:新建态、就绪态、阻塞/等待态、运行态、退出态;
    创建进程分两步:执行一些必要的辅助工作(新建态)、执行进程;
    退出进程分两步:终止进程使进程转换到退出态(保留数据方便其他程序读取)、然后真正退出进程;
    当处于新建态,程序保留在外存中,没有放到内存里。

     

    交换活动的需要

    I/O的活动比计算速度慢很多。所以会产生所有的进程都在等待I/O的情况。这个时候处理器就处于空闲的状态,且内存都满了,没有空间给新的进程了。
    一种解决方法是交换。把内存中某个进程的一部分或全部移动到磁盘中。
    挂起队列就是指这些被换出到磁盘的进程组成的队列。
    交换 是一个 I/O操作。但是由于磁盘I/O一般是系统中最快的I/O,所以交换也能提高性能。
    -->因此进程模型中又要增加一个状态,叫做挂起态。因此内存中释放的内存可以被调入的另一个进程使用。
    当操作系统已经执行了一个换出操作,它有两种选择(将一个进程取到内存中):
    一、接纳一个新创建的进程(这样做会增加负载总数);
    二、调入一个以前被挂起的进程(倾向于这个);
    所以就绪态、阻塞态就变成了4个:就绪态、阻塞态、阻塞/挂起态、就绪/挂起态;

    挂起进程的原因:
      交换:一方面是提供更多的内存空间,这样可以调入一个就绪/挂起态进程、或者增加分配给其他就绪态进程的内存;
    其他OS原因:

      挂起后台进程或工具程序进程,或者被怀疑导致问题的进程
      交互式用户请求
      定时
      父进程请求

    ====================================================

    六、进程的调度

    参考链接:进程的调度方式和调度算法总结:https://blog.csdn.net/vqtyh/article/details/78282555

    了解了进程如何被控制,进程的行为模型后,就开始考虑进程的调度问题,也就是如何协调多个进程使用CPU的问题。

    简单看下参考链接的内容,就可以了解这部分内容。

    ====================================================

    七、进程间的通信(IPC)

    多个进程之间存在信息交换的需求。

    可以分为低级通信(数据量小)、高级通信(数据量大)
    低级:信号量(互斥量(互斥锁)是特殊的信号量,临界区);PV操作是低级通信方式;
    高级:见下方;

    高级通信方式:
    一、共享存储 ->信号量通常和共享内存结合在一起,信号量用来同步对共享内存的访问;

    二、消息队列

    三、管道通信
    分为管道和FIFO。

    四、客户机-服务器系统(CS)
    1)套接字
    同一台电脑上多个应用程序之间的通信(进程间通信):解决多对进程同时通信时端口以及物理线路的多路复用问题;
    计算机网络+UNIX操作系统广泛使用——>称为最流行的网络通信程序接口 //这种通信的传输效率低,开销大,用于跨网络进程的交互多。属于I/O通信。不只在内存中玩,效率自然就低了。
    2)远程过程调用和远程方法调用


    进程的同步与互斥-->其实也属于进程的通信范畴
    临界资源的互斥访问,实现资源共享;
    信号量机制:整型信号量(表示资源的数量)、记录型信号量、

    四种进程或线程同步及互斥的控制方法;
    信号量
    互斥量
    临界区 ->前三个都可以归为信号量这个范畴;
    事件 ->这个实际上是通过管道通信机制实现的;

     

    此外从另一个角度可以总结进程间通信的方式有五种:

    进程间的五种通信方式:https://www.cnblogs.com/zgq0/p/8780893.html

    1.管道:速度慢,容量有限,只有父子进程能通讯 ;它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。   //存在于内存中的文件,不属于任何文件系统,由内核管理。

    2.FIFO任何进程间都能通讯,但速度慢。也称为命名管道,它是一种文件类型。    FIFO是Linux基础文件类型中的一种。但,FIFO文件在磁盘上没有数据块,仅仅用来标识内核中一条通道。各进程可以打开这个文件进行read/write,实际上是在读写内核通道,这样就实现了进程间通信。

    3.消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题。是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。独立于进程而存在的,在系统内存中,有内核管理的。    

    1、2、3本质上是很接近,从某个角度看都是一种模式。传统的管道队列模式采用内存缓冲区的方式,数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程,读写存在于内核缓存区的文件。

    4.信号量:不能传递复杂消息,只能用来同步      //和第五种结合使用,用于互斥和同步

    5.共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存。共享内存是由内核出于在多个进程间交换信息的目的而留出的一块内存区(段)。如果段的权限设置恰当,每个要访问该段内存的进程都可以把它映像到自己的私有地址空间中。如果一个进程更新了段中的数据,其他进程也立即会看到更新。由一个进程创建的段,也可以由另一个进程读写。每个进程都把它自己对共享内存的映像放入自己的地址空间。

    ====================================================

    八、死锁问题

    死锁的4个必要条件:https://www.cnblogs.com/bopo/p/9228834.html

    是指各并发进程彼此互相等待对方所拥有的资源。
    这些并发进程在得到对方的资源之前并不会释放自己所拥有的资源。
    从而造成大家都想得到资源而又都得不到资源,各并发进程不能继续向前推进的状态。

    产生死锁的4个必要条件
    1、互斥条件
    2、请求和保持条件
    3、不剥夺条件
    4、循环等待条件

    产生死锁的原因
    1、系统资源不足;
    2、进程推进顺序非法;

     

    死锁如何解决?

    互斥锁:
    信号量用于多线程同步,一个线程完成率某一个动作就通过信号告诉别的线程,别的线程再进行某些动作。

    互斥锁是用于多线程互斥,一个线程占用了某一个资源,那么别的资源就无法访问,直到这个线程离开,其他线程才可以利用这个资源。

    也就是说互斥锁已经备某线程加锁,如果此线程再去加锁则无效,也就是说互斥锁只能加锁一次。

    临界区:
    保证某一时刻只能有一个线程能访问数据的简便方法,
    在任意时刻只允许一个线程对共享资源进行访问。
    如果有多个线程试图同事访问临界区,那么在有一个线程进入后其他所有试图访问次临界区的线程将被挂起,并一直持续到进入临界区的线程离开。

    ====================================================

    九、继续讨论信号量

    用于解决线程之间的同步
    多个并发的进程彼此之间围绕着紧俏的资源产生了两种关系:同步或互斥;
    信号量正是解决资源竞争的最有效途径。

    举例:
    信号量是一个非负整数(车位数),所有通过它的线程(车辆)都会将该整数减一。当该整数值为零时,所有试图通过它的线程都将处于等待状态。

    信号量定义两种操作:Wait(等待)和Release(释放);
    这是一个原子操作;

    当一个线程调用Wait操作时,它要么得到资源然后将信号量减一,要么一直等下去(指备放入阻塞队列),直到信号量大于等于一时。
    Release实际上是在信号量上执行加操作。对应于车辆离开停车场,该操作之所以叫释放,是因为释放了信号量守护的资源。

    信号量守护资源。解决线程之间调用资源而产生的竞争关系。
    信号量的操作是原子操作;

     

    信号量分为两种:计数信号量、二进制信号量;
    二进制信号量,又称为互斥锁。

    V操作:增加信号量的数值;signal操作, 释放信号量;
    P操作(pending):减少数值;:wait操作,sleep操作,获取信号量;
    对信号量的访问具有原子性

    ====================================================

    相关链接:

    进程详解(1):https://www.cnblogs.com/jacklu/p/5317406.html

    进程与线程:https://www.cnblogs.com/qianqiannian/p/7010909.html 

    进程概念:https://www.jianshu.com/p/d35d67b829ab

    进程的基本概念:https://www.cnblogs.com/mlgjb/p/8241718.html

    进程间通信FIFO:https://blog.csdn.net/qq1113231395/article/details/88824916

    详解linux进程间通信-消息队列: https://www.cnblogs.com/liudw-0215/p/8978945.html

  • 相关阅读:
    算法复习———dijkstra求次短路(poj3255)
    NOIP2017年11月9日赛前模拟
    NOIP2017赛前模拟11月6日—7日总结
    刷题总结——子串(NOIP2015)
    NOIP2017赛前考试注意事项总结
    NOIP2017赛前模拟11月4日总结:
    NOIP2017赛前模拟11月2日总结
    刷题总结——Aeroplane chess(hdu4405)
    刷题总结——Interval query(hdu4343倍增+贪心)
    刷题总结——Throw nails(hdu4393)
  • 原文地址:https://www.cnblogs.com/grooovvve/p/11605178.html
Copyright © 2011-2022 走看看