【Linux】详解进程终止进程等待

一、页表&&写时拷贝的进一步理解

        页表中不仅仅只有虚拟地址到物理地址的映射,还包括了很多选项,其中就包括了映射条目的权限。当我们进程的代码和数据加载到内存并和进程地址空间建立映射关系时,如果数据的内容不允许被修改(比如说常量字符串),对应数据在页表中的映射条目的权限就会被设置为'r',表示该数据是只读的,不能被修改。这就是为什么当我们要对常量字符串的内容做修改程序运行阶段会报错的底层原因。

        通过页表的权限位,我们也可以很好地解释写时拷贝是如何做到的。当父进程创建子进程时会发生写时拷贝,写时拷贝会把大部分映射条目的权限都由‘rw’设置成‘r’。当子进程或者是父进程要对数据进行修改时,发现要修改数据对应的映射条目的权限位‘r’,无法进行修改,这时操作系统就会介入。操作系统发现子进程(假设是子进程要对数据进行修改)要对数据进行修改,且操作时合法的,这是就会在内存中申请一块空间重新建立映射关系,再将父子进程该对应的映射条目都改成‘rw’,这才算完成了一次写时拷贝。通过以上过程操作系统就可以按需进行写时拷贝。

二、进程终止

        main函数的返回值我们叫做进程的退出码。一般0表示进程执行成功,非0表示进程执行失败可以用非0的数字表示进程失败的原因。错误码可以转换成错误描述,可以使用语言和系统自带的方法进行转化,也可以自定义。其他函数错误码仅仅表示函数调用结束。

2.1、echo $?

        bash进程会记录最近一个进程退出的退出码,可以查看echo $?可以查看最近一个进程退出的退出码。

        调用函数我们通常想看到两种结果,一是函数的执行结果(比如说fopen打开文件,打开成功就返回文件指针,打开失败返回NULL,这叫函数的执行结果),二是函数的执行情况(比如说同样是fopen打开文件,我们函数的执行情况对应的数字会被保存在errno(错误码)这个变量中)。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main()
{
    FILE* fp = fopen("./log.txt", "r");
    printf("%d %s\n", errno, strerror(errno));
    return 0;
}

 错误码和main函数的退出码本质上是一样的。 错误码只会记录系统提供的函数的执行情况

2.2、进程退出的场景

进程提出的场景与三种:

1、进程代码执行完了,结果是正确的。

2、进程代码执行完了,结果不正确。

3、进程代码没有执行完,进程出异常了。进程出异常时,进程的退出码是没有意义的。

         第三种情况进程出异常是进程收到了操作系统发出的异常信号,每个信号都有不同的编号,不同的信号编号表示异常的原因。

        任何进程最终的执行情况我们都可以用两个数字来表示。一个是进程的退出信号(exit_signal)(退出信号为0表示进程没有出异常),一个是进程的退出码(exit_code)进程的退出信号是由操作系统发送给进程,以指示进程应该终止或进行某种操作的信号,是上对下的操作。而进程的退出码则是当进程结束运行时返回给操作系统的一个整数值,用于表示进程的执行状态或结果,是下对上返回的结果。

2.3、exit

        exit就是用来终止进程的,exit括号中的内容就是进程的退出码。在我们的代码进程中,在任意地方调用exit都表示进程退出

三、进程等待

3.1、进程等待的必要性

1、之前讲过,子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存泄漏。

2、另外,进程一旦变成僵尸状态,那就刀枪不入,kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。

3、最后,父进程派给子进程的任务完成的如何,我们需要知道。如子进程运行完成,结果对还是不对,或者是否正常退出。

4、父进程通过进程等待(wait)的方式,回收子进程资源,获取子进程退出信息

 3.2、进程等待的方法

3.2.1、wait方法

        wait方法里的参数为输出型参数,可以设置为NULL。调用wait函数父进程默认进行阻塞等待,会等待任意一个子进程退出。等待成功,wait会返回子进程的pid,等待失败返回小于0的值。 

        fork之后父子进程谁先运行不确定,但fork之后一定是父进程后退出,因为父进程要回收子进程。

3.2.2、waitpid方法

        以上pid参数为要回收子进程的pid(pid如果为-1,表示等待任意一个子进程,与wait等效),wstatus参数同样为输出型参数,可以设置为NULL(也可以设置为一个int变量的地址,可以查看子进程的退出码), options参数设置为0表示阻塞等待,设置为宏 WNOHANG表示非阻塞等待采用非阻塞的方法等待,子进程退出成功返回子进程的pid,子进程还在继续自己的工作返回0,子进程出错返回小于0的数。阻塞等待时父进程会阻塞在waitpid这里一直等待子进程返回,非阻塞等待采用轮询的方法查看子进程的退出信息,在轮询的间隙父进程可以继续做别的工作。

3.2.3、wstatus参数详解

        *wstatus表示一个int整形变量,由三十二个比特位组成,其中前16个比特位我们不用,第17到第24个比特位用来表示进程退出时的退出码,第26到第32个比特位用来表示进程退出时收到的退出信号。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>


int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        // child
        int cnt = 5;
        while(cnt)
        {
            printf("Child is running, pid: %d, ppid: %d\n", getpid(), getppid());
            sleep(1);
            cnt--;
        }
        exit(1);
    }
    int status = 0;
    pid_t rid = waitpid(id, &status, 0); // 阻塞等待
    if(rid > 0)
    {
        printf("wait success, rid: %d, status: %d\n", rid, status);
    }

    return 0;
}

 

        这就可以解释为什么上面的status变量为256了。因为子进程的退出码为1,status的第24个比特位被设置为1,没有收到退出信号,所以status后8个比特位都为0,所以status等于2的8次方等于256。 

3.2.4、使用位操作从status变量中提取出进程的退出信号和退出码。

int main()
{
    pid_t id = fork();
    if(id == 0)
    {

        int cnt = 5;
        while(cnt)
        {
            printf("Child is running, pid: %d, ppid: %d\n", getpid(), getppid());
            sleep(1);
            cnt--;
        }
        exit(1);
    }
    int status = 0;
    pid_t rid = waitpid(id, &status, 0); // 阻塞等待
    if(rid > 0)
    {
        printf("wait success, rid: %d, status: %d, exit_signal: %d, exit_code: %d\n", rid, status, status&0x7f, (status>>8)&0xff);
    }

    return 0;
}

 3.2.5、使用宏获取进程的退出码

        一般用户不是很关心进程的退出状态只想获取子进程的退出码就可以使用这种方法。

WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)。

WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)。

int main()
{
    pid_t id = fork();
    if(id == 0)
    {

        int cnt = 5;
        while(cnt)
        {
            printf("Child is running, pid: %d, ppid: %d\n", getpid(), getppid());
            sleep(1);
            cnt--;
        }
        exit(1);
    }
    int status = 0;
    pid_t rid = waitpid(id, &status, 0); // 阻塞等待
    if(WIFEXITED(status))
    {

       printf("wait success, rid: %d, status: %d, exit_code: %d\n", rid, status,WEXITSTATUS(status));
    }


    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/493955.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

阿里云服务器多少钱一个月?低至5元1个月

阿里云服务器一个月多少钱&#xff1f;最便宜5元1个月。阿里云轻量应用服务器2核2G3M配置61元一年&#xff0c;折合5元一个月&#xff0c;2核4G服务器30元3个月&#xff0c;2核2G3M带宽服务器99元12个月&#xff0c;轻量应用服务器2核4G4M带宽165元12个月&#xff0c;4核16G服务…

elementui日期时间选择框自定义组件

1.需求场景 业务中需要&#xff0c;日期选择框方便客户对日期的选择&#xff08;比如近5天&#xff0c;本周&#xff0c;本月&#xff0c;本年等等&#xff09;&#xff0c;并按小时展示。 2.组件代码MyDateTimeChange.vue <template><el-date-pickerv-model"…

Rust使用原始字符串字面量实现Regex双引号嵌套双引号正则匹配

rust使用Regex实现正则匹配的时候&#xff0c;如果想实现匹配双引号&#xff0c;就需要使用原始字符串字面量&#xff0c;不然无法使用双引号嵌套的。r#"..."# 就表示原始字符串字面量。 比如使用双引号匹配&#xff1a; use regex::Regex;fn main() {println!(&qu…

c# RichTextbox添加行号

使用另一个RichTextBox放在要添加行号的左边 使用以下代码 //uiRichTextBox1为右侧文本框&#xff0c;uiRichTextBox2为左侧文本框int lineIndex 0;private void uiRichTextBox1_TextChanged(object sender, EventArgs e){if (lineIndex > uiRichTextBox1.Lines.Length){L…

全国地质灾害点shp崩塌滑坡泥石流空间分布地质灾害详查等数据集

地质灾害是指在自然或者人为因素的作用下形成的&#xff0c;对人类生命财产造成的损失、对环境造成破坏的地质作用或地质现象。地质灾害在时间和空间上的分布变化规律&#xff0c;既受制于自然环境&#xff0c;又与人类活动有关&#xff0c;往往是人类与自然界相互作用的结果。…

【项目技术介绍篇】如何在本地运行若依项目

作者介绍&#xff1a;本人笔名姑苏老陈&#xff0c;从事JAVA开发工作十多年了&#xff0c;带过大学刚毕业的实习生&#xff0c;也带过技术团队。最近有个朋友的表弟&#xff0c;马上要大学毕业了&#xff0c;想从事JAVA开发工作&#xff0c;但不知道从何处入手。于是&#xff0…

Java——注解和注释

0 注解和注释的区别 在博主刚开始学习java语言的时候&#xff0c;经常把注释和注解搞混淆&#xff0c;误认为这两个是类似的东西&#xff0c;其实它们完全不是一个东西。 注释&#xff1a; 注释是程序员在代码中添加的说明性文字&#xff0c;用于解释代码的功能、目的或实现…

在ubuntu上编译prometheus

大纲 系统环境编译环境默认的版本GolangNodejsNPM 更新Nodejs和NPMNodejsNPM 编译运行 prometheus的编译并不难&#xff0c;核心是要将编译环境配置到符合要求的地步&#xff0c;否则就会出现各种错误&#xff0c;而且难以排查。 我们主要需要关心go、npm和nodejs的版本。 以下…

前端Web移动端学习day05

移动 Web 第五天 响应式布局方案 媒体查询Bootstrap框架 响应式网页指的是一套代码适配多端&#xff0c;一套代码适配各种大小的屏幕。 共有两种方案可以实现响应式网页&#xff0c;一种是媒体查询&#xff0c;另一种是使用bootstrap框架。 01-媒体查询 基本写法 max-wid…

饼图渲染的关键

1) 创建一个DOM对象,有自定义的高和宽. 2) 引入Echarts软件包并导入到对应文件内 npm i Echarts import 文件.js script src.../文件 3) 初始化一个对象 4) 对象的方法实现饼图渲染 data内的数据,且当一个对象已经渲染一遍,再执行这个,会对setOption的参数进行更新,其…

定制化区块链交易所开发:Dapp、DeFi和IDO的全方位解决方案

随着区块链技术的不断发展&#xff0c;区块链交易所已经成为数字资产交易的主要场所之一。然而&#xff0c;由于不同项目的需求和特点各不相同&#xff0c;通用的交易所往往无法满足所有的需求。因此&#xff0c;定制化区块链交易所的需求逐渐增加&#xff0c;以满足不同项目的…

JVM(六)——内存模型与高效并发

内存模型与高效并发 一、java 内存模型 【java 内存模型】是 Java Memory Model&#xff08;JMM&#xff09; 简单的说&#xff0c;JMM 定义了一套在多线程读写共享数据时&#xff08;成员变量、数组&#xff09;时&#xff0c;对数据的可见性、有序 性、和原子性的规则和保障…

MySQL修改root用户的密码

在Windows上重置MySQL的root用户密码可以通过以下步骤进行&#xff1a; 停止MySQL服务&#xff1a;使用快捷键WINR打开运行窗口&#xff0c;输入cmd进入命令行。在命令行中输入net stop mysql来关闭MySQL服务。启动MySQL跳过授权表&#xff1a;将目录切换到MySQL安装目录下的b…

CSMM软件过程能力成熟度模型

软件过程能力成熟度模型旨在通过提升组织的软件开发能力帮助顾客提升软件的业务价值。 本模型借鉴吸收了软件工程、项目管理、产品管理、组织治理、质量管理、卓越绩效管理、精益软件开发等领域的优秀实践&#xff0c;为组织提供改进和评估软件过程能力的一个成熟度模型。 总体…

腾讯云4核8G12M云服务器一年646元,送3个月时长

2024年腾讯云4核8G服务器租用优惠价格&#xff1a;轻量应用服务器4核8G12M带宽646元15个月&#xff0c;CVM云服务器S5实例优惠价格1437.24元买一年送3个月&#xff0c;腾讯云4核8G服务器活动页面 txybk.com/go/txy 活动链接打开如下图&#xff1a; 腾讯云4核8G服务器优惠价格 轻…

C语言程序编译与链接(拓宽视野的不二之选)

文章目录 翻译环境和运行环境翻译环境预处理编译汇编链接 运行环境 翻译环境和运行环境 1&#xff0c;在ANSI C的任何⼀种实现中&#xff0c;存在两个不同的环境。 第1种是翻译环境&#xff0c;在这个环境中源代码被转换为可执⾏的机器指 令&#xff08;⼆进制指令&#…

文生图大模型Stable Diffusion的前世今生!

1、引言 跨模态大模型是指能够在不同感官模态(如视觉、语言、音频等)之间进行信息转换的大规模语言模型。当前图文跨模态大模型主要有&#xff1a; 文生图大模型&#xff1a;如 Stable Diffusion系列、DALL-E系列、Imagen等 图文匹配大模型&#xff1a;如CLIP、Chinese CLIP、…

由浅到深认识Java语言(29):集合

该文章Github地址&#xff1a;https://github.com/AntonyCheng/java-notes 在此介绍一下作者开源的SpringBoot项目初始化模板&#xff08;Github仓库地址&#xff1a;https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址&#xff1a;https://blog.c…

【深度学习基础(4)】pytorch 里的log_softmax, nll_loss, cross_entropy的关系

一、常用的函数有&#xff1a; log_softmax,nll_loss, cross_entropy 1.log_softmax log_softmax就是log和softmax合并在一起执行&#xff0c;log_softmaxlogsoftmax 2. nll_loss nll_loss函数全称是negative log likelihood loss, 函数表达式为&#xff1a;f(x,class)−x[…

Django开发复盘

一、URL 对于一个不会写正则表达式的蒟蒻来说&#xff0c;在urls.py中就只能傻傻的写死名字&#xff0c;但是即便这样&#xff0c;还会有很多相对路径和绝对路径的问题&#xff08;相对ip端口的路径&#xff09;&#xff0c;因为我们网页中涉及到页面跳转&#xff0c;涉及到发送…