4.进程简介

4 进程

在本章中,我们将讨论操作系统为用户提供的最基本的抽象之一:进程(process)。 非正式地说,进程的定义很简单:一个运行的程序[V + 65,BH70]。 程序本身是一个没有生命的东西:它只是位于在磁盘上,包括一堆指令(以及一些静态数据),等待开始行动。 操作系统读取这些字节并使其运行,将程序转换为有用的程序。 事实证明,人们经常想要同时运行多个程序;例如,考虑您可能喜欢在桌面或笔记本电脑上运行Web浏览器,邮件程序,游戏,音乐播放器等的。 事实上,典型的系统似乎可能同时运行数十甚至数百个进程。 这样做可以使系统易于使用,人们不需要关心CPU是否可用,只需要运行程序。 因此我们的挑战:

问题关键:如何提供多个CPU的错觉?

尽管这里只有很少的物理CPU可以使用,OS如何提供多个的CPU的错觉?

操作系统通过虚拟化CPU来创建这种错觉。 通过运行一个进程,然后停止它并运行另一个进程,等等,操作系统可以提供许多虚拟CPU存在的错觉,而实际上只有一个物理CPU(或几个)。 这种基本技术称为CPU的分时(time sharing),允许用户根据需要运行尽可能多的并发进程;潜在的成本是性能,因为如果共享CPU,每个进程都会运行得更慢。

为了很好的实现CPU虚拟化,OS同时需要底层的机制(mechanisms)和高层的策略(policies)。

机制是实现所需功能的低级方法或协议。 例如,我们稍后将学习如何实现一个上下文转换(context switch),它使操作系统能够停止运行一个程序并在给定的CPU上开始运行另一个程序; 所有现代操作系统都采用这种分时机制。

策略是OS做出某种决策的算法。 例如,考虑到在CPU上运行的许多可能的程序,操作系统应该运行哪个程序? 操作系统中的调度策略将做出此决定,可能使用历史信息(例如,哪个程序在最后一分钟运行得更多?),工作负载知识(例如,运行的程序类型)以及性能指标 (例如,系统是否优化交互性能或吞吐量?)来做出决定。

提示:使用分时(和空间共享(space sharing))

分时是操作系统用来共享资源的基本技术。 通过允许资源由一个实体使用一段时间,然后由另一个实体使用一段时间,资源(例如,CPU或网络链路)可以由许多人共享。 分时的对应物是空间共享,其中资源在希望使用它的人之间被(空间)划分。 例如,磁盘空间自然是空间共享资源,一旦将块分配给文件,在用户删除原始文件之前,通常不会将其分配给另一个文件。

4.1 进程

OS对运行的程序提供的抽象我们称之为进程。如上所述,一个进程就是一个正在运行的程序。在任何时刻,我们都可以通过对其在执行过程中访问或影响的系统的不同部分进行盘点,来总结一个进程。

为了理解进程的构成,我们必须了解其机器状态(machine state):程序在运行时可以读取或更新的内容。在任何给定时间,机器的哪些部分对执行该程序很重要?

包含进程的机器状态的一个明显组成部分是其内存。指令存于内存中,运行程序读写的数据也在内存中。因此,进程可以寻址的内存(称为其地址空间)是进程的一部分。

进程的机器状态的一部分是寄存器。许多指令明确地读取或更新寄存器,因此它们对于执行过程很重要。

请注意,有一些特殊的寄存器构成了这种机器状态的一部分。 例如,程序计数器PC)(有时称为指令指针( instruction pointer,IP))告诉我们当前正在执行哪个程序指令。类似地,堆栈指针和相关的指针用于管理函数参数,局部变量和返回地址的堆栈。

最后,程序通常也访问持久存储设备。 此类I/O信息可能包括进程当前打开的文件列表。

4.2 进程API

虽然我们将讨论真实的进程API推迟到后续章节,但在这里我们首先要了解操作系统的任何接口中必须包含的内容。这些API以某种形式可用于任何现代操作系统。

  • 创建:操作系统必须包含一些创建新流程的方法。在shell中键入命令或双击应用程序图标时,将调用操作系统创建一个新进程来运行您指定的程序。
  • 销毁:由于存在用于创建进程的接口,因此系统还可以提供强制摧毁进程的接口。当然,许多进程都会在完成之后自行完成;然而,当他们不这样做时,用户可能希望杀死他们,因此停止失控进程的接口非常有用。、
  • 等待:有时等待进程停止运行是有用的;因此经常提供某种等待接口。
  • 杂项控制:除了杀死或等待进程之外,有时可能还有其他控制措施。例如,大多数操作系统提供某种方法来暂停进程(阻止它运行一段时间)然后恢复它(继续运行)。
  • 状态:通常还有接口来获取有关进程的某些状态信息,例如运行的时间或状态。

4.3 进程的创建

程序如何转化为进程,具体来说,操作系统如何启动并运行程序?进程创建实际上如何运作?

操作系统为了运行程序必须做的第一件事是将其代码和任何静态数据(例如,初始化变量)加载(load)到进程的地址空间中。程序最初以某种可执行格式驻留在磁盘上(或者,在某些现代系统中,基于闪存的SSD);将程序和静态数据加载到内存中的过程要求操作系统从磁盘读取这些字节并将它们放在内存中(如图4.1所示)。

在早期(或简单)操作系统中,加载过程是在运行程序之前完成的,即一次完成,现代操作系统懒惰(lazily)地执行该过程,即仅在程序执行期间根据需要加载代码或数据。要真正了解代码和数据的延迟加载是如何工作的,您必须更多地了解分页((paging)和交换((swapping)机制,我们将在讨论内存虚拟化时讨论这些主题。现在只需要记住,在运行任何东西之前,操作系统显然必须做一些工作才能将程序的重要字节从磁盘放入内存。

将代码和静态数据加载到内存后,操作系统在运行该进程之前还需要执行一些其他操作。必须为程序的运行时堆栈(run-time stack)(或仅堆栈(stack))分配一些内存。正如您可能已经知道的那样,C程序将堆栈用于局部变量,函数参数和返回地址。操作系统分配此内存并将其提供给进程。操作系统也可能会使用参数初始化堆栈,具体来说,它将填充main())函数的参数,即argc和argv数组。

操作系统还可以为程序的(heap)分配一些内存。在C程序中,堆用于显式请求的动态分配数据,程序通过调用malloc()来请求这样的空间,并通过调用free()来明确地释放它。数据结构需要堆,例如链表,哈希表,树和其他有趣的数据结构。堆最初会很小,当程序运行并通过malloc()库API请求更多内存时,操作系统可能会参与并为进程分配更多内存以帮助满足此类调用。

操作系统还将执行一些其他初始化任务,尤其是与输入/输出(I/O)相关的任务。例如,在UNIX系统中,默认情况下每个进程都有三个打开的文件描述符,用于标准输入,输出和错误。这些描述符使程序可以轻松地从终端读取输入以及将输出打印到屏幕。我们将在本书的第三部分中详细了解有关持久性的I/O,文件描述符等。

通过将代码和静态数据加载到内存中,通过创建和初始化堆栈,以及通过执行与I/O设置相关的其他工作,操作系统现在(最终)为程序执行设置了阶段。因此它有一个最后的任务:启动在入口点运行的程序,即main()。通过跳转到main()方法(通过我们将在下一章讨论的专用机制),OS将CPU的控制权转移到新创建的进程,从而程序开始执行。

4.4 进程状态

既然我们已经知道一个进程是什么(虽然我们将继续改进这个概念),并且(大致)如何创建它,让我们谈谈一个进程在给定时间可以处于的不同状态。过程可以处于这些状态之一的概念出现在早期的计算机系统中[DV66,V + 65]。 在简化视图中,进程可以处于以下三种状态之一:

  • Running:在运行状态下,进程正在处理器上运行。 这意味着它正在执行指令。
  • Ready:处于就绪状态,进程已准备好运行但由于某种原因,操作系统已选择不在此时刻运行它。
  • Blocked:在阻塞状态下,进程已执行某种操作,使其在其他事件发生之前无法运行。 一个常见示例:当进程向磁盘发起I / O请求时,它会被阻塞,因此其他一些进程可以使用该处理器。

如果我们将这些状态映射到图表,我们将得到图4.2中的图表。 正如您在图中看到的那样,根据操作系统的判定,进程可以在准备状态和运行状态之间移动。 从准备运行到运行意味着该过程已被调度(scheduled);从运行转移到准备就绪意味着该过程已被取消调度(descheduled)。 一旦进程被阻塞(例如,通过启动I/O操作),OS将保持这样直到某些事件发生(例如,I/O完成),此时,进程再次进入就绪状态(如果操作系统决定,可能会立即再次运行)。

让我们通过其中一些状态了解进程。 首先,假设有两个进程在运行,每个进程只使用CPU(它们没有I/O)。 在这种情况下,每个进程的状态跟踪可能如下所示(图4.3)。

在下一个示例中,第一个进程在运行一段时间后发出I/O。此时,该进程被阻止,使另一个进程有机会运行。图4.4显示了这种情况的痕迹。更具体地说,进程0启动I/O并被阻塞等待它完成;例如,从磁盘读取或等待来自网络的数据包时,进程会被阻止。操作系统识别进程0未使用CPU并开始运行进程1。在进程1运行时,I/O完成,将进程0恢复为就绪状态。最后,进程1完成,进程0运行然后完成。

请注意,即使在这个简单的示例中,操作系统也必须做出许多决定。首先,当进程0发出I/O,系统必须决定运行进程1,这样做可以通过保持CPU忙碌来提高资源利用率。其次,系统决定在其I/O完成时不切换回进程0,目前尚不清楚这是否是一个好的决定。你怎么看?这些类型的决策是由OS调度程序做出的,我们将在未来讨论几个章节。

4.5 数据结构

操作系统是一个程序,与任何程序一样,它有一些跟踪各种相关信息的关键数据结构。例如,为了跟踪每个进程的状态,操作系统可能会为所有就绪的进程保留某种进程列表,以及跟踪当前正在运行的进程的一些其他信息。操作系统还必须以某种方式跟踪被阻止的进程;当I/O事件完成时,操作系统应确保唤醒正确的进程并准备再次运行。

图4.5显示了操作系统需要跟踪xv6内核[CK + 08]中每个进程的信息类型。类似的进程结构存在于“真实”操作系统中,例如Linux,Mac OS X或Windows。查看它们,看看它们有多复杂。从图中,您可以看到操作系统跟踪过程的几个重要信息。对于已停止的进程,寄存器上下文将保持其寄存器的内容。当进程停止时,其寄存器将保存到该存储器位置。通过恢复这些寄存器(即,将它们的值放回实际的物理寄存器中),OS可以完成整个过程。在接下来的章节中,我们将更多地了解这种被称为上下文切换的技术。

/*
 * the registers xv6 will save and restore
 * to stop and subsequently restart a process
 * 当停止和重启进程时,xv6会保存和恢复的寄存器
 */
struct context {
    int eip;
    int esp;
    int ebx;
    int ecx;
    int edx;
    int esi;
    int edi;
    int ebp;
};
/* 进程可能的状态*/
enum proc_state { UNUSED, EMBRYO, SLEEPING,
          RUNNABLE, RUNNING, ZOMBIE };
/*
 * xv6跟踪每个进程的信息,包括寄存器上下文和状态
 */
struct proc {
    char    * mem;                 /* Start of process memory */
    uint    sz;                    /* Size of process memory */
    char    * kstack;              /* Bottom of kernel stack */
/* for this process */
    enum proc_state     state;     /* Process state */
    int         pid;               /* Process ID */
    struct proc     * parent;      /* Parent process */
    void            * chan;        /* If non-zero, sleeping on chan */
    int         killed;            /* If non-zero, have been killed */
    struct file     * ofile[NOFILE]; /* Open files */
    struct inode        * cwd;       /* Current directory */
    struct context      context;     /* Switch here to run process */
    struct trapframe    * tf;        /* Trap frame for the */
/* current interrupt */
};

Figure 4.5: The xv6 Proc Structure

您还可以从图中看到,除了运行,准备和阻止之外,还有一些其他状态可以进入。 有些系统为刚创建的进程提供初始状态。 此外,可以将进程置于已退出但尚未清除的最终状态(在基于UNIX的系统中,这称为僵尸(zombie)状态)。 这个最终状态非常有用,因为它允许其他进程(通常是创建进程的父进程)检查进程的返回值并查看刚刚完成的进程是否成功执行(通常,基于UNIX的系统中,程序成功执行返回0,否则为非0)。 完成后,父进程将进行最后一次调用(例如,wait())以等待子进程完成,并向操作系统表明它可以清理任何涉及现已死去进程的相关数据结构。

旁注:数据结构 - 进程列表

操作系统充满了各种重要的数据结构,我们将在这些注释中讨论。 进程列表是第一个这样的结构。 它是一个比较简单的结构,任何能够同时运行多个程序的操作系统都会有类似于这种结构的东西,以便跟踪系统中所有正在运行的程序。 有时人们会将存储过程信息的个体结构称为进程控制块(Process Control Block,PCB)。

4.6 总结

我们已经介绍了操作系统的最基本的抽象:进程。 它被简单地视为一个正在运行的程序。 考虑到这种概念性观点,我们现在将继续讨论实质性过程:实现进程所需的低层机制,以及以智能方式调度进程所需的高层政策。 通过结合机制和策略,我们将建立对操作系统如何虚拟化CPU的理解。

原文地址:https://www.cnblogs.com/redreampt/p/9410850.html

时间: 2024-10-01 07:18:36

4.进程简介的相关文章

Linux守护进程简介和实例详解

简介 守护进程(Daemon)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种很有用的进程.Linux的大多数服务器就是用守护进程实现的.比如,Internet服务器inetd,Web服务器httpd等.同时,守护进程完成许多系统任务.比如,作业规划进程crond,打印进程lpd等. 下面是linux系统中常见的一些守护进程. amd:自动安装NFS(网络文件系统)守侯进程apmd:高级电源管理 Arpwatch:记录日志并构建一个在L

20181128linux进程简介

linux进程简介 一.什么是进程?进程是已启动的可执行程序的运行实例,进程有以下组成部分: 已分配内存的地址空间 安全属性,包括所有权凭据和特权 程序代码的一个或多个执行线程 进程状态程序:二进制文件,静态/bin/date,/usr/sbin/httpd ,/usr/sbin/sshd,/usr/local/nginx/sbin/ngix进程:是程序运行的过程,动态,有生命周期及运行状态二.进程的生命周期父进程复制自己的地址空间(fork)创建一个新的(子)进程结构.每个新进程分配一个唯一的

Linux内核剖析 之 进程简介

1.概念 1.1  什么是进程? 进程是程序执行的一个实例,可以看作充分描述程序已经执行到何种程度的数据结构的汇集. 从内核观点看,进程的目的就是担当分配系统资源(CPU时间,内存等)的实体. 我们熟悉的fork()库函数,它有两种用法: (1).一个父进程希望复制自己,使父子进程执行不同的代码段,常用于网络服务程序. (2).一个进程要执行一个不同的程序,fork()后立即exec(),如shell. 1.2  什么是线程? 有时候,一个进程希望有多个执行流,如一款麻将游戏,三个由电脑控制的人

进程简介

一,进程的概念: 内核的功用:进程管理.文件系统.网络功能.内存管理.驱动程序. 安全功能等: Process:  运行中的程序的一个 副本,是被 载入内存的一个指令集合进程ID (Process ID ,PID )号码被用来标记各个进程UID .GID .和SELinux 语境决定对文件系统的存取和 访问权限,通常从执行进程的 用户来继承存在生命周期: task struct :Linux 内核存储进程信息的数据结构格式: task list :多个任务的的task struct 组成的链表:

GNU Linux syslog守护进程简介及syslog日志写入例子

rsyslog进程 syslog是记录系统中的日志记录的一个工具,可以支持本地的.也可以支持远程的日志的写入. 在LinuxMint环境中,基于upstart的机制的后台守护程序是放在/etc/init/目录下的,可使用下如下的命令进行查看具体的启动脚本: [email protected]:/var/log$ less /etc/init/rsyslog.conf 查看当前rsyslogd是否已经启动: [email protected]:/var/log$ initctl list | gr

[python] 线程简介

参考:http://www.cnblogs.com/aylin/p/5601969.html 我是搬运工,特别感谢张岩林老师! python 线程与进程简介 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分配.任务的调度. 程序是运行在系统上的具有某种功能的软件,比如说浏览器,音乐播放器等. 每次执行程序的时候,都会完成一定的功能,比如说浏览器帮我们打开网页,为了

【Android 系统开发】 Android 系统启动流程简介

Android 系统启动总结 : Android 系统启动分底层 Linux 内核启动 和 应用系统启动; -- 底层系统启动 : 系统上电, bootloader 启动, linux kernel 启动, init 进程启动; -- 应用系统启动 : init 进程启动关键的进程如 Zygote 进程 和 System Server 等系统服务, 之后进入 Home 界面; 一. Android 底层系统启动流程(Bootloader Kernel init) 1. 系统上电 执行 ROM 引

Linux 守护进程的原理与实现

一.守护进程概述 在linux或者unix操作系统中在系统的引导的时候会开启很多服务,这些服务就叫做守护进 程.为了增加灵活性,root可以选择系统开启的模式,这些模式叫做运行级别,每一种运行级别以一定的方式配置系统. 守护进程是脱离于终端并且在后台运行的进程.守护进程脱离于终端是为了避免进程在执行过程中的信息在任何终端上显示并且进程也不会被任何终端所产生的终端 信息所打断. 二.守护进程简介 守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程.它是一个生存期较长 的进程,通

嵌入式 Linux进程间通信(三)——守护进程

嵌入式 Linux进程间通信(三)--守护进程 一.守护进程简介 1.守护进程简介 守护进程(Daemon)是运行在后台.独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件的一种特殊进程.守护进程常常在系统引导装入时启动,在系统关闭时终止.Linux的大多数服务器就是用守护进程实现的.比如,Internet服务器inetd,Web服务器httpd等.同时,守护进程完成许多系统任务.比如,作业规划进程crond等.守护进程的创建本身并不复杂,复杂的是各种版本的Unix的实现机制不尽相同