【Linux系统】进程控制

server/2024/12/22 9:49:23/

再次理解进程

进程:内核的相关管理数据结构(task_struct(进程控制块PCB),mm_struct(地址空间),页表) + 代码和数据

那么如何理解进程具有独立性

我们之前已经学习过进程控制块啊,地址空间啊,页表啊,他们不都是随着进程的创建而被创建,所以每个进程都有独立的一份这三个结构,那代码是共享的,数据是经过写时拷贝实现进程之间的独立的。

fork函数的返回

fork子进程返回0

fork父进程返回是子进程的pid

为什么父进程返回的是子进程的PID,给子进程返回的是0!!!

首先我们为了父进程方便对子进程进行标识,进而进行管理。

退出码?退出信号?

我们在写c/c++main函数的时候我们是不是往往都会写一个return 0来结束程序的运行!

为什么?

我们在命令行中使用echo $?内键命令

会发现打印出我们刚刚通过./运行的程序的main函数的返回值,我们把return后面设置为什么就会为我们返回什么!

我们知道,内键命令打印的都是bash内部的变量数据。

所以父进程bash获取到的是,最近一个子进程退出的退出码

告诉关心方(父进程),我任务完成的怎么样了!

实际上0代表成功,非0代表失败。

这是程序的退出码

1、2、3……不同的非零值,一方面表示失败,一方面表示失败的原因,

它们都有对应的错误描述,可以以字符串的形式打印出来!

父进程bash为什么要得到子进程的退出码呢?

这是要知道子进程的退出情况(成功,失败,失败的原因是什么?)

这些不都是为了让我们用户看到吗,为我们用户负责!!!

退出码不仅可以使用默认的,也可以进行自定义!

进程的终止

1.进程的终止在做什么?

释放曾经的代码和数据所占用的空间

释放内核数据结构(task_struct)-->我们知道子进程结束,父进程一直在跑但什么事情都不做,子进程进入Z(僵尸态),此时就是task_struct仍然存在的原因,这样就会造成内存泄露的问题。

那么进程的终止不就是回收资源,防止内存泄露吗!

2.进程终止的三种情况?

a.代码跑完,结果正确

可以通过进程的退出码决定!!!

b.代码跑完,结果不正确

同样可以通过进程的退出码决定!!!

c.代码执行时,出现了异常,提前退出了

两个原因,一个系统检测到错误,异常退出,一个我们人为自定义!0退出码

异常退出?(本质是因为进程收到了OS发给进程的信号!)

vs编程运行的时候,崩溃了 --- 操作系统发现你的进程做了不该做的事情,OS杀了进程,一旦出现异常,退出码没有意义了!!!

我为什么出现了异常?原因是?进程出异常,本质是因为进程收到了OS发给进程的信号!

我们可以写一段野指针的操作代码来观察现象

我们发现运行时是出现了段错误,OS提前终止进程。

当我们启动一个进程也可以用kill -11 pid来终止一个进程,其实这就是我们手动发给进程一个信号,让进程异常终止,报的也就是上面的段错误,所以进程出异常,本质是因为进程收到了OS发给进程的信号!

我们可以看进程退出的时候,退出信号是多少,就可以判断我的进程为什么异常了!!!

总结

所以我们面对程序出现错误,两步判断就可

  1. 先确认是否是异常
  2. 不是异常就一定是代码跑完了,看退出码就行。

最后,我们说衡量一个进程退出,我们只需要两个数字退出码,退出信号

这些都是要让父进程bash知道。

其实退出码,退出信号就是在我们的task_struct源代码中的两个个变量

inr exit_code,int exit_signal

3.如何终止?

a.main函数return表示进程终止(非main函数return,函数结束)

b.代码调用exit函数(注意:我们代码的任意位置调用exit,都表示进程退出)

c._exit() --- system call 系统调用接口

exit与_exit都可以让进程退出,那么它俩有什么区别呢?

exit vs _exit:exit会在进程退出的时候,充刷缓冲区,_exit不会,其实这是因为exit是c语言的库函数,它的底层还会调用_exit这个系统调用接口,来操作操作系统,所以充刷缓冲区应该在exit函数用户层的操作。

注意:目前我们说的缓冲区不是内核缓冲区!!!

4.进程等待?

是什么?

结论:任何子进程,在退出的情况下,一般必须要被父进程进行等待。进程在退出的时候,如果父进程不管不顾,退出进程,状态Z(僵尸态),造成内存泄漏。

为什么?

1.父进程通过等待,解决子进程退出的僵尸问题,,回收系统资源(一定要考虑的)

2.获取子进程的退出信息,知道子进程是因为什么原因退出的(可选的功能)

怎么办?

父进程可以通过调用wait/waitpid函数来做到上面两个事情

pid_t wait(int* status)

如果子进程没有退出,父进程其实一直在进行阻塞等待

参数部分,等待父进程中,等任意一个子进程退出。

返回值,等待成功时,子进程的pid。

进程阻塞等待?

子进程本身就是软件,父进程本质是在等待某种软件条件就绪,你如何理解阻塞等待子进程呢?

status是什么呢?

这里就要讲讲waitpid了

pid_t waitpid(pid_t pid,int* status,int options)

返回值

当正常返回时waitpid返回收集到的子进程的进程id

如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0

如果调用中出错则返回-1,这时errno会被设置成相应的值以指示错误所在

参数

pid:

pid=-1,等待任一个子进程,与wait等效

pid>0,等待其进程ID与pid相等的子进程

status:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
options:
WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进
程的ID。
 

  • 如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源,获得子进程退出信息。
  • 如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞。
  • 如果不存在该子进程,则立即出错返回。
  • wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
  • 如果传递NULL,表示不关心子进程的退出状态信息。
  • 否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。
  • status不能简单的当作整形来看待,可以当作位图来看待。

所以status其实是个输出型参数,我们学过scanf函数,我们从键盘输入数据输出到一个变量中,status就类似把进程退出码与进程退出信号输出到status中,以便父进程拿到子进程的退出信息。

那status是如何存储进程退出码与进程退出信号两个数据呢?

其实status是使用了32位比特位来存储,用status的后7位来存储终止信号,第8位存储core dump(后面讲),再往后8位存储的是进程退出信息,再往后尚未使用。

 测试代码:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>void ChildRun()
{int *p = NULL;int cnt = 5;while(1){printf("I am child process, pid: %d, ppid:%d, cnt: %d\n", getpid(), getppid(), cnt);sleep(1);cnt--;*p = 100;}
}int main()
{printf("I am father, pid: %d, ppid:%d\n", getpid(), getppid());pid_t id = fork();if(id == 0){// childChildRun();printf("child quit ...\n");exit(123);}sleep(7);// father//pid_t rid = wait(NULL);int status = 0;pid_t rid = waitpid(id, &status, 0);if(rid > 0){printf("wait success, rid: %d\n", rid);}else{printf("wait failed !\n");}sleep(3);printf("father quit, status: %d, child quit code : %d, child quit signal: %d\n", status, (status>>8)&0xFF, status & 0x7F);
}

运行结果

这个就是因为段错误,出现异常,进程异常退出!

进程的非阻塞式等待方式代码

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{pid_t pid;pid = fork();if (pid < 0) {printf("%s fork error\n", __FUNCTION__);return 1;}else if (pid == 0) { //childprintf("child is run, pid is : %d\n", getpid());sleep(5);exit(1);}else {int status = 0;pid_t ret = 0;do{ret = waitpid(-1, &status, WNOHANG);//非阻塞式等待if (ret == 0) {printf("child is running\n");}sleep(1);} while (ret == 0);if (WIFEXITED(status) && ret == pid) {printf("wait child 5s success, child return code is :%d.\n", WEXITSTATUS(status));}else {printf("wait child failed, return.\n");return 1;}}return 0;
}

执行结果! 


http://www.ppmy.cn/server/42189.html

相关文章

华为昇腾310B1平台深度学习算法模型转换

目录 1 模型转换(集成nms算子到模型中) 1.1 基础模型说明 1.2 模型转换 1.2.1 设置环境变量 1.2.2 安装yolov5依赖&#xff08;gcc需要>7.5&#xff09; 1.2.3 转换fp16模型 2 模型转换(使用atc&#xff0c;不集成nms算子) 参考文献&#xff1a; 1 模型转换(集成nms…

[NSSRound#1 Basic]sql_by_sql

[NSSRound#1 Basic]sql_by_sql 这题没啥难的&#xff0c;二次注入盲注的套题 先注册&#xff0c;进去有个修改密码 可能是二次注入 修改密码处源码 <!-- update user set password%s where username%s; -->重新注册一个admin-- 获得admin身份&#xff08;原理看sqli-l…

【C/C++】内存分布

本文第一部分主要介绍了程序内存区域的划分以及数据的存储。第二部分有一段代码和一些题目&#xff0c;全面直观得分析了程序中的数组在内存中的存储。 因为不同的数据有不同的存储需求&#xff0c;各区域满足不同的需求&#xff0c;所以程序内存会有区域的划分。 根据需求的不…

高并发缓存服务的构建要点与陷阱

1. 缓存基础与特征 在讨论高并发环境下构建缓存服务的问题前&#xff0c;我们需要先了解缓存的基础和特征。缓存&#xff08;Cache&#xff09;是一种高速数据存储层&#xff0c;它可以存储临时数据&#xff0c;以便将来的请求能更快地获取到这些数据。从本质上讲&#xff0c;…

Spring Boot | SpringBoot 中 自定义 “用户授权管理“ : 自定义“用户访问控制“、自定义“用户登录控制“

目录: 一、SpringBoot 中 自定义 "用户授权管理" ( 总体内容介绍 ) :二、 自定义 "用户访问控制" ( 通过 "HttpSecurity类" 的 authorizeRequests( )方法来实现 "自定义用户访问控制" ) :1.基础项目文件准备2.实现 "自定义身份认…

07-Fortran基础--Fortran指针(Pointer)的使用

07-Fortran基础--Fortran指针Pointer的使用 0 引言1 指针&#xff08;Poionter&#xff09;的有关内容1.1 一般类型指针1.2 数组指针1.3 派生类(type)指针1.4 函数指针 2 可运行code 0 引言 Fortran是一种广泛使用的编程语言&#xff0c;特别适合科学计算和数值分析。Fortran 9…

网络安全与信息安全

主要内容&#xff1a;1、密码学、鉴别 2、访问控制、计算机病毒 3、网络安全技术 4、安全服务与安全机制 5、信息系统安全体系结构框架 6、信息系统安全评估准则 一、密码学 1、密码学是以研究数据保密为目的&#xff0c;对存储或者传输的信息采取秘密的交换以防止第三者对信息…

MySQL--增、删、改、查,

数据库的概述、发展、现状、历史、分类 MySQL关系型数据库、架构&#xff08;C/S&#xff09; window系统安装MySQL数据库 Linux系统【选学】 数据库对象——数据库&#xff08;database&#xff09; show、create、drop命令 数据库对象——表&#xff08;table&#xff…