[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。

相关推荐
黄油烤菠萝4 分钟前
蓝桥杯-卡java排序
c++·算法·蓝桥杯
梦回阑珊12 分钟前
《QT从基础到进阶·七十四》Qt+C++开发一个python编译器,能够编写,运行python程序改进版
c++·python·qt
ツ箫声断丶何处莫凭栏90214 分钟前
C++中的多态和模板
c语言·开发语言·c++
the_nov1 小时前
19.TCP相关实验
linux·服务器·网络·c++·tcp/ip
明月醉窗台1 小时前
Qt 入门 1 之第一个程序 Hello World
开发语言·c++·qt
hy____1232 小时前
类与对象(中)(详解)
开发语言·c++
wen__xvn2 小时前
c++STL入门
开发语言·c++·算法
Y淑滢潇潇2 小时前
RHCSA Linux 系统创建文件
linux·运维·服务器
University of Feriburg2 小时前
4-c语言中的数据类型
linux·c语言·笔记·学习·嵌入式实时数据库·嵌入式软件
小雅痞2 小时前
C语言--统计字符串中最长的单词
c语言