您的位置:首页 > 汽车 > 时评 > 建投商务网官网_信阳市人民政府信访局_今天上海最新新闻事件_网站快速排名优化价格

建投商务网官网_信阳市人民政府信访局_今天上海最新新闻事件_网站快速排名优化价格

2024/12/21 11:39:23 来源:https://blog.csdn.net/2301_79582015/article/details/142897515  浏览:    关键词:建投商务网官网_信阳市人民政府信访局_今天上海最新新闻事件_网站快速排名优化价格
建投商务网官网_信阳市人民政府信访局_今天上海最新新闻事件_网站快速排名优化价格

1.进程介绍与概念

进程的本质是在计算机内存中运⾏的程序,但是这⼀个概念太过于⼴泛

每个应用程序运行于现代操作系统之上时,操作系统会提供一种抽象,好像系统上只有这个程序在运行,所有的硬件资源都被这个程序在使用。这种假象是通过抽象了一个进程的概念来完成的,进程可以说是计算机科学中最重要和最成功的概念之一。

进程是操作系统对一个正在运行的程序的一种抽象,换言之,可以把进程看做程序的一次运行过程;同时,在操作系统内部,进程又是操作系统进行资源分配的基本单位。

要了解进程,⾸先采⽤前⾯在操作系统基础中介绍的思想「先描述,再组织」,每⼀ 个进程本质也是⼀个结构(⼀般称为PCB(Process Control Block,进程控制 块),在Linux下的PCB称为 task_struct ),计算机将程序加载到内存,就会在 内存中添加⼀个进程,那么此时就会形成⼀个结构体,该结构体中存在进程的⼀些描 述,例如进程的在内存中的位置、进程的编号、对应数据和代码的地址等,在程序执 ⾏前,进程会被排列到⼀个数据结构,通过操作系统调度器从数据结构中取出进程就 代表对应的进程获取到CPU的使⽤权,此时就会通过对应进程的结构体中的相关数据 加载代码和数据进⾏运算、逻辑处理,从⽽到达执⾏程序的效果

这⼀过程可以看出,进程=程序代码和数据+进程结构体 进程可以粗略得分为两种:

1. 执⾏完对应代码就退出

2. ⼀直运⾏在后台,也被称为「常驻进程」

2.Linux下查看进程

⾸先,通过下⾯的C语⾔代码创建⼀个进程:

#include <stdio.h>
#include <unistd.h>int main() 
{    while(1) {printf("hello world\n");sleep(1);}return 0;
}

对应的Makefile代码如下:

TARGET=process 
SRC=process.c$(TARGET):$(SRC)gcc -o $@ $^.PHONY:clean
clean:rm -rf $(TARGET)

编译运⾏前⾯的C语⾔代码,并在Linux下查看对应进程

可以使⽤下⾯的⽅式:

ps ajx | head -1 && ps ajx | grep process# 如果存在部分干扰信息,可以使用结合管道和grep的-v指令对部分干扰信息的关键字进行过滤

上⾯的指令中的 ps ajx代表查看当前系统运⾏时所有的进程以及部分信息,直接执 ⾏就可以看到进程信息

可以看到对应的进程为:

在Linux下实际上进程都被保存在⼀个名为 proc 的⽬录下,这个⽬录不是存在于磁 盘中的⽬录,⽽是操作系统运⾏时进程出现创建的,使⽤下⾯的命令查看该⽬录:

ls /proc

proc ⽬录在根⽬录下,与 home ⽬录同级

再次运⾏前⾯的C语⾔代码,使⽤下⾯的代码查看程序进程信息以及在 proc下的位置

3.结束进程的方式

在Linux下,可以使⽤两种⽅式结束进程:

1. 快捷键 ctrl+c

2. 使⽤ kill 指令: Kill -9 进程PID

4.进程对应程序文件位置

在前⾯C语⾔程序对应的进程⽬录中除了可以看到 cwd 以外,还可以看到⼀个名为 exe 的软链接,该链接指向着⼀个路径,如下:

该路径对应的即为加载到内存中的代码和数据(进程组成的⼀部分),如果在运⾏时 将该路径下的 process ⽂件删除,此时已经运⾏的进程不会受到影响,因为对应的 代码和数据已经加载进内存,受影响的只是下⼀次⽆法直接使⽤运⾏程序的⽅式创建 进程

删除后再次查看结果如下:

5.进程PID与 PPID

PID 是Linux系统下每⼀个进程对应的⼀个编号,该编号会因为进程产⽣的时间不同 ⽽不同,例如每⼀次运⾏前⾯的C语⾔代码都会得到⼀个不同的PID

如果想获取到当前进程的 PID 可以使⽤getpid()函数 该函数原型如下:

 pid_t getpid(void);

其中p id_t 类似于 long 类型,是⼀个⻓整型,该函数不需要传递形参

在前⾯的C语⾔代码中添加该函数并打印该进程的 PID 对⽐使⽤指令查看进程信息下的PID

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main() 
{   pid_t id = getpid();while(1) {printf("hello world, pid = %d\n", id);sleep(1);}return 0;
}

可以看到PID⼀致

⼀般连续创建的进程,PID 是连续的     PID 是进程的编号    PPID 是指定进程的⽗进程的编号,当前进程也被称为对应⽗进程的⼦进程

同样,在代码中想获取到当前进程的⽗进程对应的 PPID ,可以使⽤ getppid() 函 数,原型如下:

pid_t getppid(void);

对前⾯C语⾔的代码进⾏修改,如下:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main() 
{   pid_t id = getpid();pid_t pid = getppid();while(1) {printf("hello world, pid = %d ppid = %d\n", id, pid);sleep(1);}return 0;
}

多次运⾏代码后结果如下:

可以发现,每⼀次运⾏代码, PID 都会改变,但是 PPID 始终不变,因为其⽗进程始 终是同⼀个进程,通过查看进程的指令可以找到 PID 为14901对应的⽗进程:

bash 是Linux下的指令解释器,每⼀次执⾏指令时,实际上就是将对应的指令交给 了bash,由 bash 再交给操作系统进⾏执⾏,当执⾏上⾯程序的进程时,实际上是 创建了⼀个 bash 的⼦进程,再由⼦进程执⾏对应的程序代码和数据

6.创建子进程 fork

6.1简单了解 fork函数

fork 函数原型如下:

pid_t fork(void);

在Linux编程⼿册中对 fork 的解释如下:

对应的函数返回值的解释如下:

⼤意为:成功的情况下,该函数返回⼦进程的 PID 给⽗进程,返回0给⼦进程。失败 的情况下,该函数返回-1给⽗进程,不创建任何⼦进程,并恰当设置错误代码

6.2简单使用 fork函数

根据前⾯对 fork 函数的介绍,修改前⾯的C语⾔代码如下:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main() 
{   pid_t id = fork();if(id > 0) {printf("I am prarent process, my pid = %d my ppid = %d\n", getpid(), getppid());} else if(id == 0) { printf("I am child process, my pid = %d my ppid = %d\n", getpid(), getppid());}return 0;
}

运行结果如下:

可以看到,⼦进程的 PPID 即为⽗进程 PID ,与前⾯的思想对应

7.简单了解 fork细节

上⾯的代码中⼀共存在着三个待解决的问题:

1. 使⽤ fork 创建⼦进程,为什么可以通过if 和 else if区分⼦进程和⽗进程

对于第⼀个问题来说,根据 fork 函数的返回值描述,当函数运⾏成功的情况下,会 返回⼦进程的 PID 给⽗进程, PID ⼀般都是⼤于0的,⽽⼦进程会收到 返回值为0,所以当上⾯代码中的id变量⼤于0时,就会⾛ fork 函数的 if 语句,⽽唯⼀⼀个接 收到的id⼤于0的就是⽗进程;同理,⼦进程的id变量等于0,就会⾛ else if 语句。

2. 为什么 fork 函数出现了两个返回值

对于第⼆个问题来说,实际上执⾏ fork 函数时,在返回 pid 之前就已经执⾏完了创 建⼦进程逻辑,此时⽗进程和⼦进程共享代码,但是各⾃独⽴数据,⽗进程拥有⾃⼰ 的返回值,⼦进程也拥有⾃⼰的返回值,所以此时 return 的时候是每个进程返回各 ⾃的返回值

3. 为什么两个分⽀语句if和 else if都执行了

对于第三个问题来说,当代码执⾏到 fork 函数时,会执⾏ fork 函数的内部逻辑, 再执⾏完其主逻辑代码后,就已经创建出了⼦进程(对应存在⼀个⼦进程的 task_struct ),此时⼦进程会与⽗进程共享同⼀块代码,但是⼦进程拥有⾃⼰的 数据,并使⽤⾃⼰的数据执⾏代码。⽽之所以需要共享同⼀块代码,是因为⽗进程的 代码是从硬盘中加载的,但是⼦进程的代码并不存在与硬盘,从⽽也就⽆法加载,⽽ 之所以不同的进程有着不同的数据,这是进程独⽴性的主要体现,可以⽤下图先简单 理解这个过程,具体过程会在进程地址空间讲解:

此处,⼦进程的 task_struct 实际上先是对⽗进程的task_struct 的拷⻉,再对其中的内容进⾏⼀定的修改;

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com