• 《Unix/Linux系统编程》第三章学习笔记 20201209戴骏


    Unix/Linux进程管理

    一、知识点归纳

    1.多任务处理

    一般来说,多任务处理指的是同时进行几项独立活动的能力。比如,我们经常看到有人边开车一边打电话 从某种意义上说.这些人正在进行多任务处理,尽管这样非常不好。任计算机技术中,多任务处理指的是同时执行几个独立的任务。在单处理器(单CPU)系统中一次只能执行一个任务-多任务处理是通过在不同任务之间多路复用CPU的执行时间来实现的,即将CPU执行操作从一个任务切换到另一个任务:不同任务之间的执行切换机制称为上下文切换。将一个任务的执行环境更改为另一个任务的执行环境如果切换速度足够快,就会给人一种同时执行所有任务的错觉这种逻辑并行性称为“并发”。在有多个 CPU或处理器内核的多姓理器系统中,可在不同CPU上实时、并行执行多项任务。此外,每个处理器也可以通.过同时执行不同的任务来实现多任务处理多任务处理是所有操作系统 的基础总体上说,它也是并行编程的基础。

    2.进程

    进程是对映像的执行。
    操作系统内核将一系列执行视为使用系统资源的单一实体。系统资源包括内存空间、I/O设备以及最重要的CPU时间。每个进程用一个独特的数据结构表示(PROC)。PROC结构体包含了某个进程的所有信息。
    我们来 定义一个非常简单的PROC结构体来表示进程。

    typedef struct proc(
    struct proc *next,	//	next proc pointer
    int	•ksp;	//	saved sp: at byte offset 4
    int	pid;	//	process ID
    int	Ppid;	//	parent process pid
    inc	status;	//	PROC status=FREE|READY, etc
    int	priority;	〃	scheduling priority
    int	kstackI1024];	〃	process execution stack
    }PR0C;
    

    在PROC结构体中,next是指向下一个PROC结构体的指针,用于在各种动态数据结 构(如链表和队列)中维护PROC结构体。k叩字段是保存的堆栈指针。当某进程放弃使用 CPU时,它会将执行上下文保存在堆栈中,并将堆栈指针保存在PROC.ksp中,以便以后恢 复。在PROC结构体的其他字段中,pid是标识一个进程的进程ID编号,ppid是父进程ID 编号,status是进程的当前状态,priority是进程调度优先级,kstack是进程执行时的堆栈。 操作系统内核通常会在其数据区中定义有限数量的PROC结构体,表示为:

    PROC proc[NPR0C];	// NPROC a constant, e.g. 64
    

    用来表示系统中的进程。在一个单CPU系统中,一次只能执行一个进程。操作系统内核通 常会使用正在运行的或当前的全局变量PROc指针,指向当前正在执行的PROC。在有多 个CPU的多处理器操作系统中,可在不同CPU上实时、并行执行多个进程。因此,在一个 多处理器系统中正在运行的[NCPU]可能是一个指针数组,每个指针指向一个正在特定CPU 上运行的进程。为简便起见,我们只考虑单CPU系统。

    3.多任务处理系统

    多任务处理系统,由以下几个部分组成。
    (1)type.h文件定义了系统常数和表示进程的简单PROC结构体。

    #define NPROC   9         //number of PROCs
    #define SSIXE   1024      //stack size = 1024
    
    //PROC status
    #define FREE    0
    #define READY   1
    #define SLEEP	2
    #define ZOMBIE	3
    
    typedef struct proc{
    struct proc *next;	//	next proc pointer
    int	*ksp;	//	saved stack pointer
    int	pid;	//	pid = 0 to NPROC-1
    int	PPid;	//	parent pid
    int	status;	//	PROC status
    int	priority;	//	scheduling priority
    int	kstack[SSIZE];	//	process stack
    }PROC;
    

    (2)ts.s文件在32位GCC汇编代码中可实现进程上下文切换。
    (3)queue.c文件可实现队列和链表操作函数。其中enqueue()函数按优先级将PROC输入队列中。在优先级队列中,具有相同优先级的进程按先进先出的顺序排序。
    (4)t.c文件定义MT系统数据结构、系统初始化代码和进程管理函数。

    4.进程同步

    (1)睡眠模式
    当某进程需要某些当前没有的东西时,它就会在某个事件值上进入休眠状态。为实现休眠操作,我们可以在 PROC结构体中添加一个event字段,并实现ksleep(int event)函数,使进程进入休眠状态。接下来,我们将假设对 PROC结构体进行修改以包含加粗显示的添加字段。
    (2)唤醒操作
    当某个等待时间发生时,另一个执行实体(可能是某个进程或中断处理程序)将会调用 kwakeup(event)。唤醒正处于休眠状态等待该事件值的所有程序。如果没有任何程序休眠等待该程序,kwakeup()就不工作,即不执行任何操作。

    5.进程终止

    进程能以两种方式终止:
    (1)正常终止:进程调用exit(value),发出_exit(value)系统调用来执行在操作系统内核的kexit(value).
    (2)异常终止:进程因某个信号而异常终止。信号和信号处理将在后面第6章讨论。
    在这两种情况下,当进程终止时,最终都会在操作系统内核中调用kexit()。

    6.MT系统中的进程管理

    完善基础MT系统,实现MT系统的进程管理函数:
    (1)用二叉树的形式实现进程家族树。
    (2)实现 ksleepO()和kwakeup()进程同步函数。
    (3)实现kexit()和kwait()进程管理函数。
    (4)添加"w"命令来测试和演示等待操作。

    7.Unix/Linux中的进程

    (1)进程来源
    当操作系统启动时,操作系统内核的启动代码会强行创建一个PID=0的初始进程。然后系统执行它。在初始化系统后,P0复刻一个子进程P1,并把进程切换为以用户模式运行P1。
    (2)INIT和守护进程
    P1的大部分子进程都是用来提供系统服务的。它们在后台运行,不与任何用户交互。它们被称为守护进程。
    (3)登录进程
    除了守护进程,P1复刻了许多登录进程,每个终端上一个,用于用户登录。每个登录进程打开三个与自己的终端相关联的文件流(stdin, stdout, stderr).
    (4)sh进程
    当用户成功登录时,LOGIN 进程会获取用户的 gid 和 uid,从而成为用户的进程。它将目录更改为用户的主目录并执行列出的程序,通常是命令解释程序 sh。现在,用户进程执行sh,因此用户进程通常称为 sh 进程。它提示用户执行命令。一些特殊命令,如cd(更改目录)、退出、注销等,由sh 自己直接执行。其他大多数命令是各种 bin 目录(如/bin、/sbin、/usr/bin、/usr/local/bin 等)中的可执行文件。对于每个(可执行文件)命令,sh 会复刻一个子进程,并等待子进程终止。子进程将其执行映像更改为命令文件并执行命令程序。子进程在终止时会唤醒父进程 sh,父进程会收集子进程终止状态、释放子进程 PROC 结构体并提示执行另一个命令等。除简单的命令之外,sh 还支持 I/O 重定向和通过管道连接的多个命令。
    (5)进程的执行模式
    中断:中断是外部设备发送给 CPU的信号,请求 CPU 服务。当在 Umode 下执行时,CPU 中断是启用的,因此它将响应任何中断。在中断发生时,CPU 将进入 Kmode 来处理中断,这将导致进程进人 Kmode。
    陷阱:陷阱是错误条件,例如无效地址、非法指令、除以0等,这些错误条件被 CPU识别为异常,使得 CPU 进入 Kmode 来处理错误。在 Unix/Linux 中,内核陷阱处理程序将陷阱原因转换为信号编号,并将信号传递给进程。对于大多数信号,进程的默认操作是终止。
    系统调用:系统调用(简称syscall)是一种允许 Umode 进程进入 Kmode 以执行内核函数的机制。当某进程执行完内核函数后,它将期望结果和一个返回值返回到 Umode,该值通常为0(表示成功)或-1(表示错误)。如果发生错误,外部全局变量errno(在 errno.h中)会包含一个 ERROR 代码,用于标识错误。

    8.进程管理的系统调用

    (1)进程执行顺序
    子进程与父进程和系统中所有其他进程竞争CPU运行时间。根据调度优先度的顺序,优先度的顺序,优先度动态变化。
    进程终止
    (3)等待子进程终止
    在任何时候,一个进程都可以使用int pid = wait(int *status);系统调用,等待僵尸子进程。如果成功,则wait()会返回僵尸子进程的PID,而且status包含僵尸子进程的exitCode。此外,wait()还会释放僵尸子进程,以供重新使用。

    9.I/O重定向

    (1)文件流和文件描述符
    每个文件流对应Linux内核中一个打开文件。它们都用一个文件描述符表示。
    stdin、stdout、stderr的文件描述符分别为0、1、2。
    (2)管道与管道命令
    管道是用于进程交换数据的单向进程间同此你通道。有一个读取端和一个写入端。
    在Unix/Linux中,命令行cmd1|cmd2包含一个管道符号“|”。Sh将通过一个进程运行cmd1,另一个运行cmd2。

  • 相关阅读:
    路由的使用
    组件之间的参数传递
    vue组件的全局注册和局部注册
    git版本回退(回退至上个版本,回退至指定版本) git放弃本地所有未提交的修改
    vue工程中的文件
    新建vue项目(webpack-simple)
    NPM install -save 和 -save-dev 傻傻分不清
    动态增加表单vue element ui
    JAVA声明一个对象数组
    调用测试用
  • 原文地址:https://www.cnblogs.com/daijun123/p/16749245.html
Copyright © 2020-2023  润新知