首页 > 系统相关 >[linux] 进程相关概念理解

[linux] 进程相关概念理解

时间:2023-02-04 15:31:31浏览次数:69  
标签:grep PID pro pid 理解 linux 进程 include

@​​TOC​

1. 什么是进程

[linux] 进程相关概念理解_#include


假设在一个文件中写代码,并生成一个可执行程序在磁盘中,可执行程序本质也是一个二进制文件

文件 =内容+属性

内容即 自己写的代码和数据

属性即 创建时间、权限等信息

[linux] 进程相关概念理解_子进程_02

  • 使用 ./ 将其加载到内存中,cpu访问代码和数据,从而执行代码,
    把代码和数据放入内存中 就可以叫做进程么?当然不是!
    - 举例:
    如何成为你的学校的学生呢?
    只要想办法进入你的学校里,在学校里,就是你的学校的学生么?
    当然不是,看门的大爷和楼管阿姨也在学校里
    想要成为学生,必须在学籍档案中有你个人的基本信息
    同理,只把代码和数据放入内存中,不叫作进程
    为什么基本信息在学籍档案中呢?
    因为学校要对学生管理

[linux] 进程相关概念理解_子进程_03


随着程序加载到内存的数量增多,操作系统就要考虑如何把加载的代码个数据进行管理,

所以操作系统要管理进程

管理的本质是先描述,在管理</font>​​ (不懂的可以点击查看具体解释)​

管理本质的解释

描述

[linux] 进程相关概念理解_#include_04


使用结构体构建了结构体对象,在操作系统教材中叫做 PCB ,在Linux中叫做 task_struct

并且结构体提取了所有进程的属性

同样使用各自的结构体,可以找到各自的代码和数据

组织

将结构体通过特定数据结构关联起来(以链表为例)

[linux] 进程相关概念理解_#include_05


通过链表的增删查改操作,来完成对进程的增加、删除、查找、修改

结论

进程是内核关于进程的相关数据结构+当前进程的代码和数据

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,使之无线循环下去

创建终端

[linux] 进程相关概念理解_#include_06

在第一个终端中点击右键,复制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
一个程序存在多个进程

首先创建三个终端

[linux] 进程相关概念理解_子进程_07

  • 在终端2和终端3中同时运行 ./pro ,再次在终端1中使用指令​​ps axj | head -1 && ps axj | grep pro | grep -v grep​​,发现生成两个PID值不同的进程,将一个可执行程序多次加载内存,可执行程序内部存在多个进程

查看进程方法2

​ls /proc​​,proc 为process的简称,保存进程相关属性的目录

[linux] 进程相关概念理解_父进程_08

  • 蓝色的数字就是进程的PID
查看成功
  • 在保证终端1正在运行./pro,在终端2中以第一次生成的PID为例

[linux] 进程相关概念理解_#include_09

  • PID值为3943,​​ls proc/3943​​,即可查看相关的进程属性

[linux] 进程相关概念理解_子进程_10

查看失败
  • 若将终端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​​,显示当前进程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​​,头文件为<unistd.h> ,返回值是 pid_t类型

#include<stdio.h>
2 #include<sys/types.h>
3 #include<unistd.h>
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<stdio.h>
2 #include<sys/types.h>
3 #include<unistd.h>
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<stdio.h>
2 #include<sys/types.h>
3 #include<unistd.h>
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<stdio.h>
2 #include<sys/types.h>
3 #include<unistd.h>
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个<font color=red>fork之后,谁先运行由调度器决定,fork之后,fork之后的代码共享,通常通过if和else if来进行执行流分流

6. fork 原理

1.fork做了什么

[linux] 进程相关概念理解_父进程_11

子进程pcb的大部分属性会以父进程pcb为模板,把父进程大部分里面的数据拷给子进程
小部分属于子进程私有的,例如PID、PPID值 因为进程等于数据结构+代码和数据,所以父进程指向自己的代码和数据,子进程也会指向同样的代码和数据 ,创建子进程:创建独立的pcb结构,父子进程看到的是同一份代码和数据

2.fork 如何看待代码和数据

[linux] 进程相关概念理解_子进程_12

当我们把画图关闭后,并不会影响有道云笔记的使用,说明他们都是独立存在的,进程在运行的时候,是具有独立性的 当我们在执行代码同时运行父子进程时,若使用 kill- 9 干掉父进程后,子进程仍能运行 父子进程在运行时,也是具有独立性的

父子进程指向同一块代码和数据,独立性如何保证?

代码: 代码在内存区域是只读的(从来不会自己发生变化,不会有人修改) 父子进程两者都读,不会互相影响 数据:

1 #include<stdio.h>  
2 #include<sys/types.h>
3 #include<unistd.h>
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值不变 说明如果有一个进程把数据改了,并不会影响另一个进程 当有一个执行流尝试修改数据的时候,操作系统自动给当前进程触发:写时拷贝

3.fork如何理解两个返回值问题

[linux] 进程相关概念理解_子进程_13

  • 当我们函数内部准备执行return的时候,我们的主体功能已经完成
  • fork本质上是操作系统提供的一个创建子进程的函数
  • 所以当到return时,说明创建子进程已经完成了,return语句,父进程会执行一次,子进程执行一次,共执行两次

标签:grep,PID,pro,pid,理解,linux,进程,include
From: https://blog.51cto.com/u_15787387/6037178

相关文章

  • linux系统优化、用户权限
    linux系统优化、用户权限系统优化相关1.了解自己的系统情况cat/etc/redhat-release#简要查看系统情况uname-r/-a/-n/-s/...#2.用户信息创建用户:usera......
  • Linux日志文件/var/log详解
    如果愿意在Linux环境方面花费些时间,首先就应该知道日志文件的所在位置以及它们包含的内容。在系统运行正常的情况下学习了解这些不同的日志文件有助于你在遇到紧急情况时从......
  • 通过一个示例形象地理解C# async await 非并行异步、并行异步、并行异步的并发量控制
    前言接上一篇通过一个示例形象地理解C#asyncawait异步我在.NET与大数据中吐槽前同事在双层循环体中(肯定是单线程了)频繁请求es,导致接口的总耗时很长。这不能怪前同......
  • 项目开发中的linux系统的常用常用命令
    nginx启动nginx:./nginx(有点)重启nginx:./nginx-sreload开启指定端口号:(例子为开启6379)firewall-cmd--zone=public--add-port=6379/tcp--permanent查看jar包命令:psaux|gre......
  • 理解
      理解是一个非常抽象的词语,很难用具体的实例说明理解的真正含义,理解好像更多的是一种心灵的感应,一种基于文化背景、知识背景等诸多背景之下对同样的事情、处境可以达到......
  • 开放远程端口后服务器日志中很多登录进程NtLmSsp攻击的处理办法
    首先按住键盘“Windows+R”键,在运行窗口输入“secpol.msc”,并点击“确定”进入安全设置》本地策略》安全选项,然后下图两个配置项中二选一即可,按照第一个配置项,则日志彻......
  • Linux新手渣渣上路史
    时至2022年,IT行业的迅速发展大家也有目共睹,IT行业在社会的发展中起着举足轻重的作用。其中一角Linux系统,从诞生到开源,再到现在受大众的欢迎,是一个很好的例子。Linux和windo......
  • Linux ALSA驱动之四:Control设备创建流程源码分析(5.18)
    Control接口主要让用户空间的应用程序(​​alsa-lib​​​)可以访问和控制​​音频​​​codec芯片中的多路开关,滑动控件等。对于​​Mixer​​​(混音)来说,Control接口显得尤......
  • linux中mysql安装
    #首先通过yum下载wget命令1.yum-yinstallwget#通过wget下载MySQL存储库2.wgethttps://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm3.rpm-Uvhmy......
  • Linux系统之网络安全管理
    (Linux系统之网络安全管理)一、Firewalld介绍Firewalld是一个动态防火墙管理器,它是nftables框架的前端(使用nfs命令),firewalld曾使用iptables命令来直接配置iptables......