帮助文档
专业提供香港服务器、香港云服务器、香港高防服务器租用、香港云主机、台湾服务器、美国服务器、美国云服务器vps租用、韩国高防服务器租用、新加坡服务器、日本服务器租用 一站式全球网络解决方案提供商!专业运营维护IDC数据中心,提供高质量的服务器托管,服务器机房租用,服务器机柜租用,IDC机房机柜租用等服务,稳定、安全、高性能的云端计算服务,实时满足您的多样性业务需求。 香港大带宽稳定可靠,高级工程师提供基于服务器硬件、操作系统、网络、应用环境、安全的免费技术支持。
服务器资讯 / 香港服务器租用 / 香港VPS租用 / 香港云服务器 / 美国服务器租用 / 台湾服务器租用 / 日本服务器租用 / 官方公告 / 帮助文档
【linux】进程-查看进程-PID值-fork原理
发布时间:2024-02-27 20:48:47   分类:帮助文档
【linux】进程|查看进程|PID值|fork原理 文章目录 1. 什么是进程管理本质的解释描述组织 结论 2.查看进程查看进程方法1创建终端输入命令显示进程一个程序存在多个进程 查看进程方法2查看成功查看失败结论 3.通过系统调用获取进程标识符1.获取PID值验证PID值是否正确 2. 获取父进程PID值验证3. 父进程为什么不变化?4. 为什么都是bash? 4.指定进程暂停5.如何创建子进程1. fork返回值2.使父子进程执行不同的任务3. 结论 6. fork 原理1.fork做了什么2.fork 如何看待代码和数据父子进程指向同一块代码和数据,独立性如何保证? 3.fork如何理解两个返回值问题 1. 什么是进程 假设在一个文件中写代码,并生成一个可执行程序在磁盘中,可执行程序本质也是一个二进制文件 文件 =内容+属性 内容即 自己写的代码和数据 属性即 创建时间、权限等信息 使用 ./ 将其加载到内存中,cpu访问代码和数据,从而执行代码, 把代码和数据放入内存中 就可以叫做进程么?当然不是! - 举例: 如何成为你的学校的学生呢? 只要想办法进入你的学校里,在学校里,就是你的学校的学生么? 当然不是,看门的大爷和楼管阿姨也在学校里 想要成为学生,必须在学籍档案中有你个人的基本信息 同理,只把代码和数据放入内存中,不叫作进程 为什么基本信息在学籍档案中呢? 因为学校要对学生管理 随着程序加载到内存的数量增多,操作系统就要考虑如何把加载的代码个数据进行管理, 所以操作系统要管理进程 管理的本质是先描述,在管理 (不懂的可以点击查看具体解释) 管理本质的解释 描述 使用结构体构建了结构体对象,在操作系统教材中叫做 PCB ,在Linux中叫做 task_struct 并且结构体提取了所有进程的属性 同样使用各自的结构体,可以找到各自的代码和数据 组织 将结构体通过特定数据结构关联起来(以链表为例) 通过链表的增删查改操作,来完成对进程的增加、删除、查找、修改 结论 进程是内核关于进程的相关数据结构+当前进程的代码和数据 2.查看进程 查看进程方法1 #include 2 #include 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 需要头文件 ,返回值为 getpid_t类型,表示当前进程的PID值 #include 2 #include 3 #include 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 2 #include 3 #include 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,显示当前进程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 在终端1中多次运行./pro,发现当前进程PID一直在变,而父进程的PID没变过父进程的PID为32452,在终端2中输入, ps ajx | head -1 && ps ajx |grep 32452 指令 [yzq@VM-8-8-centos lesson]$ ps ajx | head -1 && ps ajx |grep 32452 PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 907 3167 3166 907 pts/3 3166 R+ 1002 0:00 grep --color=auto 32452 32451 32452 32452 32452 pts/2 32452 Ss+ 1002 0:00 -bash 说明父进程PID 为 -bash bash为命令行解释器,本质上也是一个进程 命令行启动的所有程序,最终都会变成进程,而该进程对应的父进程都是bash 4. 为什么都是bash? bash怕你写的代码有问题,所以使用bash创建的子进程完成任务,这样就算是挂了,bash也没事 4.指定进程暂停 在终端1中运行./pro,在终端2中输入 kill - 9+自己进程的PID [yzq@VM-8-8-centos lesson]$ ./pro 我已经是一个进程了,PID为:29031,我的父进程PID为:28428 我已经是一个进程了,PID为:29031,我的父进程PID为:28428 我已经是一个进程了,PID为:29031,我的父进程PID为:28428 我已经是一个进程了,PID为:29031,我的父进程PID为:28428 我已经是一个进程了,PID为:29031,我的父进程PID为:28428 我已经是一个进程了,PID为:29031,我的父进程PID为:28428 我已经是一个进程了,PID为:29031,我的父进程PID为:28428 我已经是一个进程了,PID为:29031,我的父进程PID为:28428 我已经是一个进程了,PID为:29031,我的父进程PID为:28428 我已经是一个进程了,PID为:29031,我的父进程PID为:28428 我已经是一个进程了,PID为:29031,我的父进程PID为:28428 我已经是一个进程了,PID为:29031,我的父进程PID为:28428 我已经是一个进程了,PID为:29031,我的父进程PID为:28428 我已经是一个进程了,PID为:29031,我的父进程PID为:28428 Killed 在终端2中输入 kill - 9 29031,即可在终端1中显示killed,表示结束 5.如何创建子进程 创建子进程—— fork,头文件为 ,返回值是 pid_t类型 #include 2 #include 3 #include 4 int main() 5 { 6 printf("AAAA\n"); 7 fork(); 8 printf("BBBB\n"); 9 sleep(1); 10 return 0; 11 } 继续在终端1中修改pro.c文件中的内容如上 [yzq@VM-8-8-centos lesson]$ ./pro AAAA BBBB BBBB 运行pro可执行程序,发现竟然执行两次BBBB 这是为什么呢?我们继续往下看 #include 2 #include 3 #include 4 int main() 5 { 6 printf("AAAA\n"); 7 fork(); 8 printf("BBBB:pid:%d,ppid:%d\n",getpid(),getppid()); 9 sleep(1); 10 return 0; 11 } 修改por.c文件的内容,加上自己和父进程的PID值 [yzq@VM-8-8-centos lesson]$ ./pro AAAA BBBB:pid:4285,ppid:31919 BBBB:pid:4286,ppid:4285 终端1中./pro运行可执行程序,两个执行B的printf语句打印自己进程的PID值不同,说明是两个进程而下面BBBB的父进程PID与上面BBBB的子进程PID相同,说明创建了子进程 1. fork返回值 父进程返回子进程的PID值,子进程返回0,失败返回-1 1 #include 2 #include 3 #include 4 int main() 5 { 6 printf("AAAA\n"); 7 pid_t ret= fork(); 8 printf("BBBB:pid:%d,ppid:%d,%d,%p\n",getpid(),getppid(),ret,&ret); 9 sleep(1); 10 return 0; 11 } 修改pro.c文件内容,加上ret的值和地址 [yzq@VM-8-8-centos lesson]$ ./pro AAAA BBBB:pid:7799,ppid:31919,7800,0x7ffefc72c02c BBBB:pid:7800,ppid:7799,0,0x7ffefc72c02c 在终端1中运行./pro,上面的BBBB,ret值返回是下面BBBB的PID值 ,说明是父进程 而下面的BBBB,ret值为0,说明是子进程 2.使父子进程执行不同的任务 #include 2 #include 3 #include 4 int main() 5 { 6 pid_t ret= fork(); 7 if(ret==0) 8 { 9 //子进程 10 while(1) 11 { 12 printf("我是子进程,我的pid是:%d,我的父进程是:%d\n",getpid(),getppid()); 13 sleep(1); 14 } 15 16 } 17 else if(ret>0) 18 { 19 //父进程 20 while(1) 21 { 22 printf("我是父进程,我的pid是:%d,我的父进程是:%d\n",getpid(),getppid()); 23 sleep(1); 24 } 25 } 26 else 27 { //报错 29 } 30 return 0; } 修改pro.c文件的内容,设置if else语句实现 [yzq@VM-8-8-centos lesson]$ ./pro 我是父进程,我的pid是:13505,我的父进程是:31919 我是子进程,我的pid是:13506,我的父进程是:13505 我是子进程,我的pid是:13506,我的父进程是:13505 我是父进程,我的pid是:13505,我的父进程是:31919 我是子进程,我的pid是:13506,我的父进程是:13505 我是父进程,我的pid是:13505,我的父进程是:31919 我是父进程,我的pid是:13505,我的父进程是:31919 我是子进程,我的pid是:13506,我的父进程是:13505 父进程和子进程是同时运行的 说明在多执行流的环境下 if和else if可以同时成立 3. 结论 fork之后,执行流会变成2个fork之后,谁先运行由调度器决定fork之后,fork之后的代码共享,通常通过if和else if来进行执行流分流 6. fork 原理 1.fork做了什么 子进程pcb的大部分属性会以父进程pcb为模板,把父进程大部分里面的数据拷给子进程 小部分属于子进程私有的,例如PID、PPID值 因为进程等于数据结构+代码和数据,所以父进程指向自己的代码和数据,子进程也会指向同样的代码和数据 创建子进程:创建独立的pcb结构,父子进程看到的是同一份代码和数据 2.fork 如何看待代码和数据 当我们把画图关闭后,并不会影响有道云笔记的使用,说明他们都是独立存在的 进程在运行的时候,是具有独立性的 当我们在执行代码同时运行父子进程时,若使用 kill- 9 干掉父进程后,子进程仍能运行 父子进程在运行时,也是具有独立性的 父子进程指向同一块代码和数据,独立性如何保证? 代码: 代码在内存区域是只读的(从来不会自己发生变化,不会有人修改) 父子进程两者都读,不会互相影响 数据: 1 #include 2 #include 3 #include 4 int main() 5 { 6 int x=100; 7 pid_t ret= fork(); 8 if(ret==0) 9 { 10 //子进程 11 while(1) 12 { 13 printf("我是子进程,我的pid是:%d,我的父进程是:%d,%d\n",getpid(),getppid(),x); 14 sleep(1); 15 } 16 17 } 18 else if(ret>0) 19 { 20 //父进程 21 while(1) 22 { 23 printf("我是父进程,我的pid是:%d,我的父进程是:%d,%d\n",getpid(),getppid(),x); 24 x=50; 25 sleep(1); 26 } 27 } 28 return 0; 29 } 在终端1中修改pro.c文件的内容 [yzq@VM-8-8-centos lesson]$ ./pro 我是父进程,我的pid是:26332,我的父进程是:21231,100 我是子进程,我的pid是:26333,我的父进程是:26332,100 我是父进程,我的pid是:26332,我的父进程是:21231,50 我是子进程,我的pid是:26333,我的父进程是:26332,100 我是父进程,我的pid是:26332,我的父进程是:21231,50 我是子进程,我的pid是:26333,我的父进程是:26332,100 我是父进程,我的pid是:26332,我的父进程是:21231,50 我是子进程,我的pid是:26333,我的父进程是:26332,100 使用./pro执行可执行程序,修改父进程中的x值后,只有父进程的x值被修改,子进程x值不变 说明如果有一个进程把数据改了,并不会影响另一个进程 当有一个执行流尝试修改数据的时候,操作系统自动给当前进程触发:写时拷贝4 3.fork如何理解两个返回值问题 当我们函数内部准备执行return的时候,我们的主体功能已经完成fork本质上是操作系统提供的一个创建子进程的函数所以当到return时,说明创建子进程已经完成了,return语句,父进程会执行一次,子进程执行一次,共执行两次
香港云服务器租用推荐
服务器租用资讯
·广东云服务有限公司怎么样
·广东云服务器怎么样
·广东锐讯网络有限公司怎么样
·广东佛山的蜗牛怎么那么大
·广东单位电话主机号怎么填写
·管家婆 花生壳怎么用
·官网域名过期要怎么办
·官网邮箱一般怎么命名
·官网网站被篡改怎么办
服务器租用推荐
·美国服务器租用
·台湾服务器租用
·香港云服务器租用
·香港裸金属服务器
·香港高防服务器租用
·香港服务器租用特价