Linux知识点 -- 进程概念(一)

Linux知识点 – 进程概念(一)


一、冯·诺伊曼体系结构

在这里插入图片描述
我们使用的计算机大部分都遵守冯·诺伊曼体系结构:

  • 存储器:内存;
  • 输入设备:键盘、摄像头、磁盘、网卡等;
  • 输出设备:显示器、音响、磁盘、网卡等;
  • 运算器:执行算术运算、逻辑运算;
  • 控制器:协调外部就绪事件;
  • CPU是运算器 + 控制器;

为什么CPU不直接和外设进行数据交互,而需要通过存储器呢?

  • 第一:从存取速度方面来说:
    CPU&&寄存器 > 内存 > 磁盘 > 光盘;
    让cpu直接和内存打交道,而不是和外设打交道,因为外设的存取速度很慢,会拖慢整机的响应速度;

  • 第二:不用内存代替磁盘是为了控制成本;

  • CPU读取数据(数据 + 代码)都要从内存中读取,站在数据的角度,我们认为CPU不和外设直接交互;

  • CPU要处理数据,需要先将外设中的数据加载到内存,站在数据的角度,外设直接和内存交互;

二、操作系统(OS)

1.概念

任何计算机系统都包含一个基本的程序集合,称为操作系统,包括:

  • 内核:进程管理、内存管理、文件管理、驱动管理;
  • 其他程序:如库函数、shell程序等;
    在这里插入图片描述

2.设计OS的目的

  • 与硬件交互,管理所有的软硬件资源;
  • 为用户程序(应用程序)提供一个良好的运行环境;

3.如何理解管理

  • 管理,是对被管理者数据的管理;
  • 拿学校来进行类比,校长是管理者,学生是被管理者,两者之间没有直接的交互,通过辅导员拿到学生的数据,由校长对学生的数据进行管理;
  • 拿到被管理者的核心数据,来进行支持管理决策;
  • 管理:先描述,再组织;
  • 先对被管理对象进行描述,再根据描述类型,定义对象,可以把对象组织成数组;之后,对学生的管理工作,变成了对数组的增删查改;

再拿银行类比操作系统:
在这里插入图片描述

  • CPU通过驱动程序来管理各种硬件,同时提供驱动接口供用户使用系统功能,各种语言、库、组件封装系统接口,shell外壳程序和图形化界面简化用户操作;

总结
计算机管理硬件:

  • 描述起来,用struct结构体;
  • 组织起来,用链表等数据结构;

4.系统调用和库函数的概念

  • 在开发角度,操作系统对外会表现为一个整体,但是会暴露自己的部分接口,供上层开发使用,这部分由操作系统提供的接口。叫做系统调用;
  • 系统调用在使用上,功能比较基础,对用户的要求也相对比较高,所以,开发者会对系统的部分调用进行适度封装,从而形成库;

三、进程概念

1.理解进程

  • 我们自己在计算机上启动一个软件,其实就是启动了一个进程;在Linux系统下,运行我们写的可执行程序,./XXX,运行的时候,其实就是在系统层面创建了一个进程;
  • Linux是可以同时加载多个程序的,可能同时存在大量的进程在操作系统中;
  • Linux管理大量进程的方法:先描述,再组织

2.描述进程

  • 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合,称为PCB
  • Linux操作系统下的PCB是:task_struct,它会被装载到内存中并包含着进程的信息;
  • 内存中可能还有大量进程的PCB,按照一定数据结构(如链表)进行排列,再由CPU进行读取,PCB中包含了进程需要运行的代码和数据的地址;
  • CPU对进程的管理,就变成了对进程PCB结构体链表的增删查改;
  • 进程 = 对应的代码和数据 + 进程对应的PCB结构体

task_struct内容分类:

  • 标示符:描述本进程的唯一标示符,用来区别其他进程;
  • 状态:任务状态,退出代码,推出信号等;
  • 优先级:相对于其他进程的优先级;
  • 程序计数器:程序中即将被执行的下一条指令的地址;
  • 内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针;
  • 上下文数据:进程执行时处理器的寄存器中的数据;
  • I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表;
  • 记账信息:可能包括处理器的时间总和,使用的时钟数总和,时间限制,记帐号等;

3.查看进程

先写一个死循环的可执行程序:
在这里插入图片描述
该程序运行时就是一个常驻的进程;
在这里插入图片描述

  • ps指令
    ps:仅显示自己的进程
    在这里插入图片描述
    可以看到,当前自己执行的进程中bash和ps;
    ps axj:显示系统中所有的进程
    在这里插入图片描述
    在所有进程中寻找myproc进程:
    在这里插入图片描述
    注:PID是该进程的ID;
    PPID是该进程的父进程的PID;

  • top指令
    top相当于资源管理器
    在这里插入图片描述

  • 在文件系统下查看进程
    ls /proc:查看进程目录,将当前运行的所有进程以文件系统的形式展示出来
    在这里插入图片描述
    通过PID寻找进程:
    在这里插入图片描述
    进入了进程工作目录;
    在这里插入图片描述
    其中cwd是当前进程的工作目录,每个进程都有一个属性,来保存自己所在的工作路径;
    exe是可执行程序所在的路径;

4.进程PID

每个进程都会都自己的PID;

  • getpid函数:在代码中获取当前进程的PID
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    与ps指令查出来的PID一致:
    在这里插入图片描述

  • kill -9 PID:杀掉该PID的进程的指令
    在这里插入图片描述

  • getppid函数:在代码中获取当前进程的父进程的PID
    在这里插入图片描述
    在这里插入图片描述

5.父子进程

  • 父进程
    在这里插入图片描述
    上图中可以看到PID为15162的进程的父进程PID为29617,而29617进程命令名为bash;
    bash就是shell命令行,命令行上所有命令都是作为bash的子进程来运行的,每一次登录都会有不同的bash进程;

  • 子进程
    fork函数:在代码中创建子进程;
    在这里插入图片描述
    fork函数有两个返回值:
    (1)失败:返回-1;
    (2)成功:给父进程返回子进程的PID,给子进程返回0;

    在这里插入图片描述
    上图代码用fork创建了子进程,运行结果如下:
    在这里插入图片描述
    fork函数后面的代码执行了两次,再加上打印PID:
    在这里插入图片描述
    执行结果:
    在这里插入图片描述
    PID也打印了不同的两个,而且下面的进程是上面进程的子进程,从返回值可以看出,父进程返回值为子进程PID,子进程返回值为0;

  • fork的基本用法
    fork之后,代码是父子共享的;
    fork的基本用法是进程分流,让父子进程执行不同的代码;
    在这里插入图片描述
    每隔1s监视系统中指定的进程的脚本
    在这里插入图片描述
    执行结果:
    在这里插入图片描述
    一份代码有两个while(1)同时执行,这是因为fork之后有两个不同的执行流
    使用if判断语句将父子进程分流,id的值在父进程里面是子进程的PID,在子进程里面是0;
    虽然父子进程共享fork之后的代码,但是经过分流后,执行的不一样;
    fork的返回值id给父进程返回的是子进程的PID,给子进程返回的是0;

  • fork函数为什么会有两个返回值
    在fork函数的逻辑中,在创建完子进程的代码逻辑完成后,在return之前,已经出现了父进程和子进程开始执行的逻辑;
    此时,如果父进程被调度了,那么就return子进程的pid,如果子进程被调度,就return 0,return语句被父子进程都执行了,因此会有两种返回值;

注:
(1)操作系统和CPU运行某一个进程,本质是从task_struct形成的队列中挑选一个task_struct,来执行它的代码
进程调度,变成了在task_struct队列中选择一个进程的过程;
(2)父子进程被创建出来,哪一个进程先运行是由操作系统的调度器决定的;

四、进程状态

1.系统层面的进程状态

  • 新建:新建一个进程;
  • 运行:task_struct结构体在运行队列中排队,就叫做运行态;
  • 阻塞:等待非CPU资源就绪;
    系统中一定是存在各种资源(不仅是CPU)的,网卡、磁盘、显卡等设备,这些设备也会存在进程使用时排队,这种队列就叫做阻塞队列;
    比如scanf函数,如果键盘不输入内容,那么该进程就一直处于阻塞状态;
  • 挂起:当内存不足的时候,操作系统通过适当的置换进程的代码和数据到磁盘,进程的状态就叫做挂起;
    如果内存不足,当前进程长时间不执行,该进程的代码和数据就会被操作系统换出到磁盘,磁盘有专门的swap分区,用于置换挂起进程的代码和数据;

进程状态演示:
代码中调用了printf:
在这里插入图片描述
查看进程状态:
在这里插入图片描述
进程状态为S;
无printf时,查看进程状态:
在这里插入图片描述
进程状态为R;
这是因为cpu的处理速度很快,在进程队列中处理时间很短,有printf表明程序需要调用外设,需要的等待时间较长,所以进程大部分时间都在阻塞队列里;

状态后面带 + ,表明进程为前台进程:进程一启动,bash命令行就不能执行命令了,且可以被键盘CTRL + C终止;

运行可执行程序时后面加&可以让进程变为后台进程,会返回该进程的PID;

./test &

在这里插入图片描述
该程序执行时会打印,当我们以后台进程方式运行:
在这里插入图片描述
返回该进程的PID,查看进程状态:
在这里插入图片描述
该进程状态变为了S,且无法使用CTRL + c停止进程,必须使用kill -9 PID的方式才能停止:
在这里插入图片描述

2.Linux系统中的进程状态

在这里插入图片描述

  • R运行状态:表明进程要么在运行中要么在运行队列中;

  • S睡眠状态:对应着上面的阻塞状态,意味着进程在等待事件完成,可中断睡眠,就是可以将进程强制唤醒,也可以被操作系统杀掉;

  • D磁盘休眠状态:不可中断睡眠,在这个状态的进程通常会等待IO的结束,不可中断就是在执行进程时,需要等待磁盘读写,此时不可被操作系统中断进程,只能让进程自动醒来;

  • T停止状态:可以通过发送SIGSTOP信号给进程来停止进程,这个被暂停的进程可以通过发送SIGCONT信号让进程继续运行,暂停只是把代码停住了,并不代表在等待资源,调试打断点就是暂停状态;

  • X死亡状态:表明该进程可被回收,只是一个返回状态,不会在任务列表里看到这个状态

  • Z僵尸状态:一个进程已经退出,但是还不允许被操作系统释放,处于一个被检测的状态,进程维持该状态是为了让父进程和操作系统来进行回收;
    僵尸进程演示:
    让子进程运行三秒后退出,父进程一直运行;
    在这里插入图片描述
    在这里插入图片描述
    我们可以看到子进程在退出后就就变为了Z状态,进程已退出,但是无法被父进程回收,还在一直被检测;
    僵尸进程会导致内存泄漏!

  • 注:当服务器压力过大时,操作系统会通过一定的手段,杀掉一些进程,来起到节省空间的作用;

3.孤儿进程

父进程先退出,子进程就称之为孤儿进程;
孤儿进程被1号init进程领养,也由它回收;

  • 孤儿进程演示:
    在这里插入图片描述
    运行结果:
    在这里插入图片描述
    可以看到父进程在5s之后就先退出了,子进程还在,变成了孤儿进程;
    孤儿进程会被1号进程领养(1号进程是init,系统本身);
    在这里插入图片描述
    在执行kill -9 17704指令后,孤儿进程就被杀掉了,因为杀掉后该进程就立马变成了Z状态,操作系统立马识别到该进程,然后回收;

猜你喜欢

转载自blog.csdn.net/kissland96166/article/details/130779274