[Linux]进程与PCB的关系,进程的基本操作

目录

前言

一、关于进程

1.进程概念

[2.进程与操作系统的管理 -- 先描述,再组织](#2.进程与操作系统的管理 -- 先描述,再组织)

3.对进程的描述---PCB

二、进程的基本操作

1.查看进程

2.结束进程

图例展示:

通过视频示范两种方式:

3.用系统调用获取进程标示符

[ps -e 显示所有进程](#ps -e 显示所有进程)

以树状结构显示进程之间的父子关系:

4.通过系统调用创建子进程

fork函数


前言

本文主要用于帮助读者理解进程的概念、进程和PCB数据结构的关系、进程的一些基本操作---包括查看进程、结束进程、通过系统调用获取进程标示符、通过系统调用创建子进程、以树状结构显示进程之间的父子关系。


一、关于进程

1.进程概念

程序是指令、数据及其组织形式的描述,进程是程序的实体。

进程就是被加载到内存中的程序,或者被运行起来的程序就叫做进程。

为什么这么说呢?

我们从前文 --- Linux从硬件到软件理解操作系统 ---可知,为了提高计算机的整体效率,CPU只会向内存中读取和写入数据,所以如果我们要运行这个程序,就必须先将其加载到内存。最后,CPU才能从内存中读取程序中的代码和数据进行运算。


2.进程与操作系统的管理 -- 先描述,再组织

根据 ---Linux从硬件到软件理解操作系统 ---我们能知道操作系统的作用就是管理

操作系统是一个进行软硬件资源管理的软件。

它通过对下管理好各种软硬件资源,来对上为用户提供良好的 (安全、稳定、高效) 运行环境。

前者是管理手段 ,后者是管理目的

总之,操作系统就是要进行管理!!!

在程序加载进内存后,操作系统要对程序进行管理,操作系统如何管理呢?

对进程的管理本质和对人的管理一样,都是对"信息"进行管理,"管理者"对信息管理来达到目的。

所以,管理进程只要管理进程数据即可。涉及管理就会涉及数据,涉及数据就会涉及"描述"(创建结构体),对进程"描述"完成后,就能"组织"进程完成管理(对结构体增删查改)。总之,这个过程就是**"先描述,再组织"**。


3.对进程的描述---PCB

我们对进程描述的结果就是PCB结构体。

进程控制块PCB (process control block):操作系统中用于描述进程的工具,其中包含的是进程属性的集合;Linux操作系统下的PCB是 task_struct,它是Linux内核的一种数据结构,其内容可以分为如下几类:

标示符: 描述本进程的唯一标示符,用来区别其他进程;

状态: 任务状态,退出代码,退出信号等;

优先级: 相对于其他进程的优先级;

程序计数器: 程序中即将被执行的下一条指令的地址;

内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针;

上下文数据: 进程执行时处理器的寄存器中的数据;

I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表;

记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等;

......

更详细的内容查看:Linux中进程控制块PCB-------task_struct结构体结构

我们简单抽象出来就是下面这样(假设task_struct使用链表进行组织):

cpp 复制代码
struct task_struct {     
  //进程的所有属性
    ... ...
  //进程对应的代码和数据的地址
    ... ...
  //下一个进程的地址
	struct task_struct* next;
};

总之,进程 = 内核PCB数据结构对象 + 数据和代码


二、进程的基本操作

1.查看进程

我们可以通过以下两种方式来查看进程:

(1) ps axj 指令配合 grep 和 管道查看指定进程:

cpp 复制代码
ps ajx | head -1;ps ajx | grep test | grep -v grep

运行进程的代码:

cpp 复制代码
  1 #include<stdio.h>
  2 #include<unistd.h>
  3 int main()
  4 {
  5   while(1)
  6   {
  7     printf("i am a process\n");
  8     sleep(1);
  9   }
 10   return 0;
 11 }

运行结果:

(2) 在 "/proc" 系统文件夹中查看所有进程:

2.结束进程

对于我们自己编写的普通进程来说,我们可以使用Ctrl + c结束;也可以使用kill -9 选项

图例展示:
通过视频示范两种方式:

结束进程示范

3.用系统调用获取进程标示符

我们可以通过使用操作系统给我们提供的系统调用接口**getpid( ) 与 getppid( )**来获取进程id和父进程id (进程ID是一个进程的唯一标识):

注:关于函数的返回值 pid_t,大家把它当作 int 看待即可,打印的时候也使用 %d;

cpp 复制代码
  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include <sys/types.h>
  4 
  5 int main()
  6 {
  7   while(1)
  8   {
  9     printf("i am a process,my id is %d,my father's id is %d    \n", getpid(), getppid());                                 
 10     sleep(1);
 11   }
 12   return 0;
 13 }
ps -e 显示所有进程
cpp 复制代码
ps -e
以树状结构显示进程之间的父子关系:
cpp 复制代码
ps -e --forest

可以看到,我们通过 getpid() 和 getppid() 函数得到的值的确是我们进程对应的id;同时,我们发现 test 进程的父进程是 bash,即 shell 外壳,我们可知 shell 为了防止自身崩溃,并不会自己去执行指令,而是会派生子进程去执行

4.通过系统调用创建子进程
fork函数

我们可以通过系统调用接口 fork 来创建子进程:

(这一部分我们在后面 进程控制 还会详细讲解)

在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。

fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:

  1)在父进程中,fork返回新创建子进程的进程ID;

  2)在子进程中,fork返回0;

  3)如果出现错误,fork返回一个负值;

cpp 复制代码
  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include <sys/types.h>                                                      
  4 int main()
  5 {                   
  6   pid_t id = fork();
  7   if (id == 0)                    
  8   {           
  9     while(1)
 10     {                                                           
 11       printf("child, pid->%d, ppid->%d\n", getpid(), getppid());
 12        sleep(1);                                                
 13     }           
 14   }              
 15   else if(id > 0)                                               
 16   {              
 17     while(1)
 18     {                                                            
 19       printf("father, pid->%d, ppid->%d\n", getpid(), getppid());
 20       sleep(1);                                                  
 21     }          
 22   }    
 23   else{                                                          
 24     printf("创建失败\n");
 25   }                         
 26   return 0; 
 32 }          

可以看到,结果和我们预期一样,子进程的 ppid 是 父进程的 pid,父进程的 ppid 是 bash,同时,对于父进程,fork 函数返回子进程的 pid,对于子进程,fork 返回 0。

相关推荐
apocelipes7 小时前
常用编程语言和库的正则表达式性能对比
c语言·c++·python·性能优化·golang·开发工具和环境
用户1204872216111 小时前
Linux驱动编译与加载
linux·嵌入式
用户8055336980317 小时前
Input 子系统架构:Core、Handler、Driver 三层是怎么协作的
linux·嵌入式
用户8055336980317 小时前
RK-Forge外设系列开篇 - 把板子从「能启动」变成「能用」:Ethernet/SPI/MMC 三个纯接线外设
linux·github·嵌入式
七歌杜金房1 天前
我终于又有了自己的 Linux 电脑
linux·debian·mac
郝学胜_神的一滴2 天前
CMake 034:生成器表达式:解耦构建时序、精简分支逻辑的终极利器
c++·cmake
tntxia2 天前
linux curl命令详解_curl详解
linux
扛枪的书生2 天前
Linux 网络管理器用法速查
linux
见过夏天2 天前
C++ 基础入门完全指南
c++
顺风尿一寸2 天前
Java Socket 内核之旅:从 SocketChannel.read() 到 tcp_recvmsg 与 epoll 的完整调用链路
linux