目录
前言
1. 系统管理
2. 进程
2.1 概念
2.2 进程的调度
2.3 描述进程-PBC
3. 查看进程
4. 通过系统调用获取进程标示符
前言
在计算机科学领域,进程是一种重要的概念,在日常学习中也经常遇到进程这个概念,那么进程到底是什么?我们又应该如何去理解,本文将为你详细解释什么是进程,以及如何在Linux环境下如何查看进程。
1. 系统管理
为什么要有系统管理?
-
对下管理好硬件资源
操作系统通过对硬件资源的管理,确保了系统的稳定、高效和安全的运行环境
-
对上提供良好的运行环境
操作系统对外会表现为一个整体,但是会暴露自己的部分接口,供上层开发使用——系统调用接口
系统调用
系统调用接口:由操作系统提供,也叫系统调用函数,这些函数是用C语言编写的函数(Linux环境)
大多数操作系统中,用户通常不允许直接访问底层硬件。用户要想调用底层硬件必须经过操作系统。
库函数
用户在使用时,可以直接调用系统调用接口,但系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,有心的开发者对部分系统调用进行了适度封装,从而形成库,有了库,就很有利于更上层用户或者开发者进行二次开发。
小结
系统调用和库函数的关系:
系统调用由系统提供,库函数由用户层提供,它们是上下层的关系
2. 进程
了解完整个计算机体系结构之后,再来探讨什么是进程
2.1 概念
什么是进程?
在教材当中的定义:加载到内存的程序、正在运行的程序等。进程究竟是什么,我们要如何去理解进程?
我们在使用电脑时,电脑可以同时启动多个程序(将多个.exe文件加载到内存),程序在运行之前,必须要把程序先加载到内存,系统要对加载到内存的(可执行)程序进行管理,如何管理? ——先描述,再组织
先描述,再组织
定义一个struct结构体,结构体包含进程几乎所有的属性字段,如:状态、优先级、标识符、内存指针字段、struct xxx *next
...
这些结构以链表的形式进行连接,通过对链表的增删查改就可以对进程进行管理。
可执行程序从磁盘加载到内存当中,没有识别标识的话,计算机就无法识别每个可执行程序,为了方便管理,于是便将每个可执行程序描述起来形成一个结构体,这个结构体也叫做进程控制块(process control block)简称PCB
计算机将每个可执行程序的PCB以链表的形式连接起来,于是就将进程的管理,转变成了对PCB增删查改。
所以什么是进程?
内核PCB对象(内核数据结构) + 可执行程序 = 进程
2.2 进程的调度
进程通过链表连接,这些进程又是怎么被调度运行的?
在CPU内部可以有一个运执行队列的数据结构,通过这个队列结构来实现对进程的调度。运行时进程可以被动态的调度,其实就是将可执行程序的PCB放入到执行队列当中。
也就是说:所有对进程的控制以及操作,只和进程的PCB有关,和进程的可执行程序无关。
PCB可以被放在任何数据结构当中,日常中的数据结构增删查改及练习,其实也就是对进程的管理方法。
2.3 描述进程-PBC
task_struct-PCB的一种
在Linux中描述进程的结构体叫做
task_struct
,task_struct
是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息
task_ struct内容分类
-
标示符: 描述本进程的唯一标示符,用来区别其他进程。
-
状态: 任务状态,退出代码,退出信号等。
-
优先级: 相对于其他进程的优先级。
-
程序计数器: 程序中即将被执行的下一条指令的地址。
-
内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
-
上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
-
I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
-
记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
-
其他信息
这些task_ struct中的数据全部都属于操作系统内部的数据。要获取这些数据(如pid),必须要调用系统调用。
3. 查看进程
了解完进程,我们在Linux环境下查看一下进程:
ps ajx
验证一下上边的结论:
我们可以在Linux环境下执行以下代码:
#include <stdio.h>
#include <unistd.h>
int main()
{
while(1)
{
printf("Hello world!\n");
sleep(1);
}
return 0;
}
将代码编译执行:
此时程序就变成了进程,我们可以使用grep筛选查看:
ps ajx | head -1 && ps ajx | grep myprocess
为什么有两个?
我们在筛查时,使用了grep指令,它也是一个程序,在执行搜索myprocess时它也是一个进程,所以第二个是grep的进程。
所以,只要程序一旦被运行运行就会产生进程
使用while循环每隔1秒筛查一次myprocess进程,注意观察筛查变化:
指令:
while :; do ps ajx | head -1 && ps ajx | grep myprocess | grep -v grep; sleep 1; done
可以根据生成的可执行程序名称进行适当修改。
可以清晰的看到一个进程的产生与结束。
4. 通过系统调用获取进程标示符
- 进程id(PID)
- 父进程id(PPID)
在Linux中,一般普通进程都要它的父进程
在Linux环境下执行下面这个程序:
#include <stdio.h>
#include <unistd.h>
#include<sys/types.h>
int main()
{
pid_t id = getpid();
pid_t fid = getppid();
while(1)
{
printf("Hello world! pid: %d ppid: %d\n",id,fid);
sleep(1);
}
return 0;
}
我们还是使用老方法,使用while循环每隔1秒筛查一次myprocess进程,注意观察筛查变化:
通过观察可以发现,每次启动时进程的id(pid)都不一样,这是因为:
每次启动的进程,都是一个新的进程。
虽然pid每次都会变,但是父进程(ppid)没有变化,那这个父进程(ppid)到底是什么?
筛查指令:
ps ajx | head -1 && ps ajx | grep 4599
我的ppid是4599,可根据自己的ppid进行修改。
筛查结果是bash,bash是我们的命令行解释器。
所以所有在命令行启动的进程,都是bash的子进程。
总结
通过深入了解进程的概念和原理,我们可以更好地理解计算机系统的运行方式,以上就是本文全部内容,希望对你有所帮助,感谢阅读!