1. 什么是进程
假设在一个文件中写代码,并生成一个可执行程序在磁盘中,可执行程序本质也是一个二进制文件
文件 =内容+属性
内容即 自己写的代码和数据
属性即 创建时间、权限等信息
使用 ./ 将其加载到内存中,cpu访问代码和数据,从而执行代码, 把代码和数据放入内存中 就可以叫做进程么?
当然不是!
- 举例:
如何成为你的学校的学生呢?
只要想办法进入你的学校里,在学校里,就是你的学校的学生么?
当然不是,看门的大爷和楼管阿姨也在学校里
想要成为学生,必须在学籍档案中有你个人的基本信息
同理,只把代码和数据放入内存中,不叫作进程
为什么基本信息在学籍档案中呢?
因为学校要对学生管理
随着程序加载到内存的数量增多,操作系统就要考虑如何把加载的代码个数据进行管理,
所以操作系统要管理进程
管理的本质是先描述,在管理 (不懂的可以点击查看具体解释)
管理本质的解释
描述
使用结构体构建了结构体对象,在操作系统教材中叫做 PCB ,在Linux中叫做 task_struct
并且结构体提取了所有进程的属性
同样使用各自的结构体,可以找到各自的代码和数据
组织
将结构体通过特定数据结构关联起来(以链表为例)
通过链表的增删查改操作,来完成对进程的增加、删除、查找、修改
结论
进程是内核关于进程的相关数据结构+当前进程的代码和数据
2.查看进程
查看进程方法1
#include<stdio.h> 2 #include<unistd.h> 3 int main() 4 { 5 while(1) 6 { 7 printf("hello world\n"); 8 sleep(1); 9 } 10 return 0; 11 }
创建一个pro.c的文件,同时生成一个可执行程序pro,使之无线循环下去
创建终端
在第一个终端中点击右键,复制SSH渠道,就会自动生成终端2
输入命令显示进程
在保证终端1的pro程序运行时,在第二个终端中
ps axj 查看当前系统中所有的进程
head -1 取第一行指令
grep pro 只查看自己的进程
grep -v grep 除了grep的内容显示出来
输入 ps axj | head -1 && ps axj | grep pro | grep -v grep,即可查看当前pro可执行程序的进程
[yzq@VM-8-8-centos ~]$ ps axj | head -1 && ps axj | grep pro | grep -v grep PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 3754 3943 3943 3754 pts/0 3943 S+ 1002 0:00 ./pro
一个程序存在多个进程
首先创建三个终端
- 在终端2和终端3中同时运行 ./pro ,再次在终端1中使用指令
ps axj | head -1 && ps axj | grep pro | grep -v grep
,发现生成两个PID值不同的进程 - 将一个可执行程序多次加载内存,可执行程序内部存在多个进程
查看进程方法2
ls /proc
,proc 为process的简称,保存进程相关属性的目录
- 蓝色的数字就是进程的PID
查看成功
- 在保证终端1正在运行./pro,在终端2中以第一次生成的PID为例
- PID值为3943,
ls proc/3943
,即可查看相关的进程属性
查看失败
- 若将终端1的pro可执行程序关闭,则进程不存在
[yzq@VM-8-8-centos ~]$ ls /proc/28439 ls: cannot access /proc/28439: No such file or directory
结论
- 当把进程创建时,proc目录下会自动创建以PID命名的目录,里面会把内存运行的属性呈现出来
- 当把进程终止时,proc目录下会自动把PID命名的目录全部删除
3.通过系统调用获取进程标识符
1.获取PID值
getpid
需要头文件 <sys/types.h> 和<unistd.h>,返回值为 getpid_t类型,表示当前进程的PID值
#include<stdio.h> 2 #include<sys/types.h> 3 #include<unistd.h> 4 int main() 5 { 6 while(1) 7 { 8 printf("我已经是一个进程了,PID为:%d\n",getpid()); 9 sleep(1); 10 } 11 return 0; 12 }
- 在之前的pro.c文件进行修改,将其内容修改为上面的,并在终端1中使用./pro 执行可执行程序
[yzq@VM-8-8-centos lesson]$ ./pro 我已经是一个进程了,PID为:28286 我已经是一个进程了,PID为:28286 我已经是一个进程了,PID为:28286 我已经是一个进程了,PID为:28286 我已经是一个进程了,PID为:28286 我已经是一个进程了,PID为:28286 我已经是一个进程了,PID为:28286
- 会生成不间断的相同PID值
验证PID值是否正确
- 再次创建一个终端,并命名为终端2,并保证上述的pro程序在终端1中运行的情况下,使用指令
ps axj | head -1 && ps axj | grep pro | grep -v grep
,发现PID值相同
[yzq@VM-8-8-centos lesson]$ ps axj | head -1 && ps axj | grep pro | grep -v grep PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 26652 28286 28286 26652 pts/0 28286 S+ 1002 0:00 ./pro
2. 获取父进程PID值
getppid
头文件与getpid
相同,返回值为父进程的PID值
1 #include<stdio.h> 2 #include<sys/types.h> 3 #include<unistd.h> 4 int main() 5 { 6 while(1) 7 { 8 printf("我已经是一个进程了,PID为:%d,我的父进程PID为:%d\n",getpid(),getppid()); 9 sleep(1); 10 } 11 return 0; 12 }
- 再次将终端1中的pro.c文件内容修改为上面
[yzq@VM-8-8-centos lesson]$ ./pro 我已经是一个进程了,PID为:1013,我的父进程PID为:32452 我已经是一个进程了,PID为:1013,我的父进程PID为:32452 我已经是一个进程了,PID为:1013,我的父进程PID为:32452 我已经是一个进程了,PID为:1013,我的父进程PID为:32452
验证
- ,在确保终端1中的pro可执行程序正在运行,打开终端2, 输入
ps axj | head -1 && ps axj | grep pro | grep -v grep
指令
[yzq@VM-8-8-centos lesson]$ ps axj | head -1 && ps axj | grep pro | grep -v grep PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 32452 1013 1013 32452 pts/2 1013 S+ 1002 0:00 ./pro
- 说明使用
getppid
查询结果正确
3. 父进程为什么不变化?
[yzq@VM-8-8-centos lesson]$ ./pro 我已经是一个进程了,PID为:2050,我的父进程PID为:32452 ^C [yzq@VM-8-8-centos lesson]$ ./pro 我已经是一个进程了,PID为:2059,我的父进程PID为:32452 ^C [yzq@VM-8-8-centos lesson]$ ./pro 我已经是一个进程了,PID为:2065,我的父进程PID为:32452 ^C