Linux进程

Posted 在下赵某人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux进程相关的知识,希望对你有一定的参考价值。

目录

一、冯诺依曼体系结构

常见的计算机,如笔记本。不常见的计算机,如服务器,大部分都遵守冯诺依曼体系。

截至目前,我们所认识的计算机,都是由一个个的硬件组件组成

  • 输入单元:包括键盘, 鼠标,扫描仪, 写板等
  • 中央处理器(CPU):含有运算器和控制器等
  • 输出单元:显示器,打印机等

关于冯诺依曼,必须强调几点:

  • 这里的存储器指的是内存
  • 不考虑缓存情况,这里的CPU能且只能对内存进行读写,不能直接访问外设(输入或输出设备)
  • 外设(输入或输出设备)要输入或者输出数据,也只能写入内存或者从内存中读取。
  • 一句话,所有设备都只能直接和内存打交道。

冯诺依曼结构规定了硬件层面上的数据流向。

为什么可执行程序运行时,必须先加载到缓存中?
存储分级概念:

CPU会和内存直接打交道,但不会直接与外设打交道。因为外设访问速度太慢,会拖累CPU效率。

请解释:A用户用QQ给B用户发了一条消息,数据的流动过程。

请解释:A用户用QQ给B用户发了一个文档,数据的流动过程。

二、操作系统(Operator System)

1. 概念
任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:

  • 内核(进程管理,内存管理,文件管理,驱动管理)
  • 其他程序(例如函数库,shell程序等等)

操作系统是进行软硬件资源管理的软件

2. 为什么要有操作系统(OS)

  • 可以减少用户使用计算机的成本
  • 对下管理好所有的软硬件,对上给用户提供一个稳定高效的运行环境

硬件:CPU、磁盘、内存… …
软件:进程管理、文件、驱动… …

3. 定位
在整个计算机软硬件架构中,操作系统的定位是:一款纯正的“搞管理”的软件

OS不信任任何用户,所以任何对系统硬件或者软件的访问都必须通过OS。

硬件部分遵守冯诺依曼体系

4. 理解 “管理”
校长是如何管理学生的呢?

  • 校长只需要管理辅导员就可以了,辅导员再去管理学生,这样校长就实现了对学生的管理。
  • 其中校长是管理者,辅导员是执行者,学生是被管理者。
  • 校长(管理者)—>辅导员(执行者)—>学生(被管理者)

类比上面的例子,操作系统如何管理软硬件呢?

操作系统(管理者)—>驱动(执行者)—>软硬件(被管理者)

管理者与被管理者并不见面, 那么具体如何进行管理呢?

  • 例如校长管理学生,只需要定义一个struct student的结构体,然后让辅导员收集并填入学生信息,最后将一个个struct student用链表链接 起来。此时学生的管理就变成了对链表的:(入学)、(开除)、(考查)、(信息修改)。

操作系统管理的也一样,将对软硬件的管理转化成对数据的管理:

  • 用struct定义新对象,用结构体描述新对象,再将struct用数据结构组织起来。

5. 总结
管理的本质:先描述,再组织。

三、系统调用和库函数概念

  • 在开发角度,操作系统对外会表现为一个整体,但是会暴露自己的部分接口,供上层开发使用,这部分由操作系统提供的接口,叫做系统调用。

  • 系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,有心的开发者可以对部分系统调用进行适度封装,从而形成库,有了库,就很有利于更上层用户或者开发者进行二次开发。

  • 操作系统存在于内存中,所以用键盘进行数据读取的本质是:

  • 接口相关

    C、C++这些语言是基于系统调用的接口,打包成库,再进行相关操作。

  • 创建进程的过程(简略)

承上启下

操作系统是怎么进行进程管理的呢?很简单,先把进程描述起来,再把进程组织起来

进程

基本概念

  • 课本概念:程序的一个执行实例,正在执行的程序等
  • 内核观点:担当分配系统资源(CPU时间,内存)的实体。

描述进程-PCB

  • 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合
  • 进程控制块也上称之为PCB,Linux操作系统下的PCB是: task_struct

task_struct-PCB的一种

  • 在Linux中描述进程的结构体叫做task_struct。

  • task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。

  • OS对进程的管理转换成为了对进程信息的管理,(对进程的管理----->双链表的增删查改)。

  • 创建进程的过程(详细)

    task_ struct内容分类

  • 标示符: 描述本进程的唯一标示符,用来区别其他进程。通常可以用一个数字来表示进程,这个标识符称之为进程的PID

  • 状态: 任务状态,退出代码,退出信号等。eg:有的进程正在运行,有的进程正在等待,有的进程被暂停了。

  • 优先级: 相对于其他进程的优先级。本质是在资源有限的前提下,确立谁先访问资源,谁后访问资源的问题。

现实中排队的本质就是确立优先级

  • 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。

PCB通过内存指针进程对应的代码和数据

  • I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
  • 记账信息: 可能包括该进程占用处理器的时间的总和,时间限制,记账号等。

不同的记账信息可能会有不同的表现

  • 程序计数器: 程序中即将被执行的下一条指令的地址。


CPU中的一个 寄存器EIP 也叫做 PC指针,同样记录了当前正在执行指令的下一条指令的地址,作用是用来指明CPU从哪里取指令。

  • 上下文数据: 进程执行时处理器的寄存器中的数据。
  1. 进程放在CPU之后,不是一直运行直到进程运行结束,每个进程都有一个运行的时间单位:时间片。一个进程在CPU上跑完一个时间片,就算该进程还未跑完,还是会换下一个进程到CPU上跑,故单CPU计算机可以同时跑多组进程。
  2. 一般进程让出CPU的情况:a. 来了一个优先级更高的进程 b. 时间片到了
  3. 单CPU跑多个进程,通过进程快速切换的方式,在一段时间内,让所有的进程代码都得到推进,叫做并发。
  4. 多CPU:任何时刻允许多个进程同时执行,叫做并行。
  5. 进程在CPU上运行,CPU寄存器上会有很多临时数据,这些数据称之为该进程的上下文数据。
  6. 当一个进程在运行中,因为某些原因,需要被暂时停止执行,让出CPU,首先该进程需要将自己的所有临时数据,存到自己的PCB中的上下文数据区域。然后将下一个进程的上下文数据覆盖到CPU的寄存器中。
  7. CPU只看PCB,操作系统会帮CPU将处于运行状态的进程的PCB组织成一个运行队列。
  8. 进程的切换就是上下文保护和恢复的一个过程。

组织进程

所有运行在系统里的进程都以task_struct链表的形式存在内核里。

查看进程

  1. getpid、getppid
  • getpid ------> 获取当前调用进程的PID

头文件:#include <unistd.h>
定义函数:pid_t getpid(void);
函数说明:getpid ()用来取得目前进程的进程识别码(PID)。
返回值:目前进程的进程识别码 (pid_t为整形类型)
范例
#include <unistd.h>
main()

printf(“pid=%d\\n”, getpid());

  • getppid ------> 获取当前调用进程的父进程的PID

头文件:#include <unistd.h>
定义函数:pid_t getppid(void);
函数说明:getppid()用来取得目前进程的父进程识别码。
返回值:目前进程的父进程识别码。
范例
#include <unistd.h>
main()

printf(“My parent 'pid =%d\\n”, getppid());

  • 进入Linux创建一个进程,该进程的父进程是谁? ------> 用getppid可知,是bash(一般情况)
  • bash在执行命令的时候往往不是由bash在进行解释和执行,而是由bash创建子进程,让子进程去执行。
  1. ps 命令
  • ps 命令是最常用的监控进程的命令,通过此命令可以查看系统中所有运行进程的详细信息。
  • ps aux 可以查看系统中所有的进程
  • 实例:
  1. top命令
    ps 命令缺乏时效性,如果需要实时监控进程运行情况,就必须不停地执行 ps 命令,而top 命令可以动态地持续监听进程地运行状态

  2. ls /proc

  • 进程的信息可以通过 /proc 系统文件夹查看
  • Linux下有一个proc目录,里面包含了很多其他目录这些目录是用数字命名的。
  • ls /proc/1 -al ------>可以认为1号进程是操作系统

通过系统调用创建进程-fork初识

  • 作用:fork创建一个子进程。例如:
  • 头文件:#include <unistd.h>
  • 定义函数:pid_t fork(void);
  • 返回值:(1) 类型:pid_t (2) fork有两个返回值,如果fork成功,会给子进程返回0,给父进程返回子进程的PID。
  • 理解fork:
  • fork 之后通常要用 if 进行分流
  • fork为什么会有两个返回值。
  • 为什么给父类返回子进程的PID?
    答:父进程有多个子进程,返回PID是用来标识子进程的。

进程状态

  • 下面的状态在kernel源代码里定义:

static const char * const task_state_array[] =
“R (running)”, /* 0 /
“S (sleeping)”, /
1 /
“D (disk sleep)”, /
2 /
“T (stopped)”, /
4 /
“t (tracing stop)”, /
8 /
“X (dead)”, /
16 /
“Z (zombie)”, /
32 */
;

  • R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
  • S睡眠状态(sleeping): 处于这个状态的进程因为等待某事件的发生而被挂起。(也叫做可中断睡眠、浅度睡眠)。

S和S+的区别:

  • D磁盘休眠状态(Disk sleep): 与S状态类似,进程处于睡眠状态,但是此状态的进程不可中断,也不可被杀掉。(也叫不可中断睡眠状态、深度睡眠)。

S: ------>是可被唤醒的,ctrl + c 程序会退出,即:随时可接收外部的信号,处理外部请求。
D: ------>深度睡眠的状态不可被杀掉,即便是操作系统也只能等待IO的结束,D状态存在的意义就在于,内核的某些处理流程是不能被打断的,否则会打断原有的流程。

  • T停止状态(stopped): 可以通过发送 SIGSTOP 信号来停止进程,这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
  • Z僵尸状态(zombie):
  1. 僵尸状态是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵尸进程。
  2. 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
  3. 只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态
  1. 进程退出一般不是立马就让OS回收释放进程的所有资源。进程退出的时候会自动将自己退出时的相关信息写入进程的PCB中,供OS读取。读取成功后,该进程才算真正释放。一个进程已经退出但还没有被读取时的状态称为僵尸状态。
  • 僵尸进程的危害:
  1. 进程的退出状态必须被维持下去,因为子进程要告诉父进程,你分配给我的任务,我办的怎么样了。
  2. 父进程如果一直不读取,那子进程就会一直处于Z状态。
  3. 维护退出状态需要用数据维护,也属于进程基本信息,所以保存在PCB中,Z状态一直不退出,PCB一直都要维护。
  4. 进程不进行回收会造成内存资源的浪费,因为数据结构对象本身就要占用内存。
  • X死亡状态(dead): 这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

进程状态总结

至此,值得关注的进程状态全部讲解完成,下面来认识另一种进程

孤儿进程

  • 父进程如果先子进程死亡,该子进程就称之为“孤儿进程”,会被1号进程领养。孤儿进程最后也会被操作系统回收。
  • 一个进程如果变成孤儿进程,会自动从前台(S+)切换到后台(S)。
  • 0号进程: 系统刚开始启动会有一个0号进程,启动后会被1号进程取代。
  • D状态和Z状态进程是无法被kill杀死。

—>未完待续

以上是关于Linux进程的主要内容,如果未能解决你的问题,请参考以下文章

如何在linux中识别一个进程是java还是c或c++进程?

linux 进程等待 wait waitpid

linux基础学习

基于LINUX下的进程管理问题

linux进程管理相关命令

在做操作系统实验的一些疑问