Linux知识点 – 进程概念(一)
文章目录
- Linux知识点 -- 进程概念(一)
- 一、冯·诺伊曼体系结构
- 二、操作系统(OS)
- 1.概念
- 2.设计OS的目的
- 3.如何理解管理
- 4.系统调用和库函数的概念
- 三、进程概念
- 1.理解进程
- 2.描述进程
- 3.查看进程
- 4.进程PID
- 5.父子进程
- 四、进程状态
- 1.系统层面的进程状态
- 2.Linux系统中的进程状态
- 3.孤儿进程
一、冯·诺伊曼体系结构
我们使用的计算机大部分都遵守冯·诺伊曼体系结构:
- 存储器:内存;
- 输入设备:键盘、摄像头、磁盘、网卡等;
- 输出设备:显示器、音响、磁盘、网卡等;
- 运算器:执行算术运算、逻辑运算;
- 控制器:协调外部就绪事件;
- 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状态,操作系统立马识别到该进程,然后回收;