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

news2024/10/1 19:58:53

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

        页表中不仅仅只有虚拟地址到物理地址的映射,还包括了很多选项,其中就包括了映射条目的权限。当我们进程的代码和数据加载到内存并和进程地址空间建立映射关系时,如果数据的内容不允许被修改(比如说常量字符串),对应数据在页表中的映射条目的权限就会被设置为'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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue 预览excel文件的又一伟大实践 —— vue-office

实际上&#xff0c;预览excel这个功能&#xff0c;我之前已经写过一个文章了。如下&#xff0c;使用的是 luckysheet/luckyExcel 实现的。 vue 实现在线预览Excel-LuckyExcel/LuckySheet实现方案_excel在线预览的方案-CSDN博客 但是最近客户使用发现一个bug&#xff0c;就是某…

vulnhub Kioptrix Level 1通关

目录 环境安装 信息收集 0X01靶机IP搜寻 1.1ifconfig查看本机IP域 1.2.nmap搜寻IP 2.直接arp-scan指令查看IP 0X02端口扫描 0X03漏洞利用 反弹shell 另一种通关方法推荐 环境安装 靶机下载&#xff1a;https://download.vulnhub.com/kioptrix/Kioptrix_Level_1.rar …

10个你必须知道的浏览器指纹检测工具,保护你的隐私安全

在当前的数字时代&#xff0c;个人隐私保护变得越来越重要&#xff0c;特别是对于互联网用户来说。有一种叫做“浏览器指纹”的技术&#xff0c;它能悄悄收集我们使用的浏览器和设备的各种细节信息。这本是为提供个性化服务&#xff0c;但对那些需要在不同平台同时管理多个账号…

应对Locked勒索病毒威胁:你的数据安全准备好了吗?

导言&#xff1a; .Locked勒索病毒&#xff0c;作为一种新型的恶意软件&#xff0c;已经在全球范围内引起了广泛的关注。这种病毒通过加密受害者的文件&#xff0c;并要求支付赎金以获取解密密钥&#xff0c;从而实现对受害者的勒索。本文旨在深入解析.Locked勒索病毒的特点、…

AXI Memory Mapped to PCI Express学习笔记(一)——PCIe事务

1 PCIe事务 AXI事务对于PCIe来说&#xff0c;主要涉及到在AXI总线和PCIe总线之间进行数据交换和通信的过程。在PCIe系统中&#xff0c;AXI总线作为一个连接不同组件的桥梁&#xff0c;可以实现高效的数据传输和事务处理。 AXI事务通常包括读事务和写事务。在读事务中&#xf…

Linux(CentOS)/Windows-C++ 云备份项目(服务器网络通信模块,业务处理模块设计,断点续传设计)

此模块将网络通信模块和业务处理模块进行了合并 网络通信通过httplib库搭建完成业务处理&#xff1a; 文件上传请求&#xff1a;备份客户端上传的文件&#xff0c;响应上传成功客户端列表请求&#xff1a;客户端请求备份文件的请求页面&#xff0c;服务器响应文件下载请求&…

Div4 898 G,H

Here G. ABBC or BACB 解题思路 一个可以向左或向右吃掉一段连续的将连续的合成一个则字符串变为每个之间被隔开统计变化后和的数量为若&#xff0c;则若&#xff0c;则只会大1&#xff0c;即有一段没被吃掉&#xff0c;则让长度最小的剩下&#xff0c;省略号间的的个数不影响…

Partisia Blockchain:真正做到兼顾隐私、高性能和可拓展的公链

目前&#xff0c;包括 Secret Network、Oasis Protocol 等在内的绝大多数以隐私为特性的可编程公链&#xff0c;在兼顾隐私的同时&#xff0c;在可拓展以及性能上或多或少的有所牺牲&#xff0c;即难以对诸多实际应用场景进行支撑。这归咎于链的设计以及共识机制的不合理&#…

C++ explicit隐式类型转换

单参数构造函数支持隐式类型的转换 什么意思&#xff1f; 简单来理解就是&#xff1a; 一个类对象的构造函数的参数只有一个&#xff0c;就可以直接进行赋值传参 例如构造函数的参数为int&#xff0c;且只有一个int 就可以直接将int类型的整型数据转换成类对象 也就是说从int类…

JavaScript、ES6与微信小程序:工具箱、升级与新房子

JavaScript、ES6和微信小程序三者之间有什么联系&#xff1f;我想&#xff0c;作为初学者还是有点蒙。下面作一个简单的分析&#xff0c;供大家参考。 首先,我们可以把JavaScript想象成一个非常强大的工具箱,里面装满了各种各样的工具。这些工具可以帮助我们完成各种任务,比如…

SpringBoot集成 itextpdf 根据模板动态生成PDF

目录 需求说明前期准备Spring Boot 集成添加依赖构建工具类构建MultipartFile编辑PDF模板Java代码设置对应form的key-value 需求说明 根据合同模板&#xff0c;将动态的合同标签&#xff0c;合同方以及合同签约时间等动态的生成PDF&#xff0c;供用户下载打印。 前期准备 安…

C语言看完我这篇编译与链接就够啦!!!

1. 前言 Hello&#xff01;大家好我是小陈&#xff0c;今天来给大家介绍最详细的C语言编译与链接。 2. 编译和链接 我们通常用的编译器&#xff0c;比如Visual Sudio,这样的IDE(集成开发环境&#xff09;一般将编译和链接的过程一步完成&#xff0c;通常将这这种编译和链接合…

腾讯云4核8G服务器性能测评_CPU内存性能_带宽流量_系统盘

腾讯云4核8G服务器价格&#xff1a;轻量4核8G12M优惠价格646元15个月、CVM S5服务器4核8G配置1437元买1年送3个月。腾讯云4核8G服务器支持多少人同时在线&#xff1f;支持30个并发数&#xff0c;可容纳日均1万IP人数访问。腾讯云百科txybk.com整理4核8G服务器支持多少人同时在线…

MySQL数据库 - 单表查询(三)

一个不知名大学生&#xff0c;江湖人称菜狗 original author: Jacky Li Email : 3435673055qq.com Time of completion&#xff1a;2024.03.24 Last edited: 2024.03.24 目录 第1关&#xff1a;对查询结果进行排序 任务描述 相关知识 对查询结果排序 指定排序方向 编程要…

设计模式之建造者模式精讲

也叫生成器模式。将一个复杂的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 在建造者模式中&#xff0c;有如下4个角色&#xff1a; 抽象建造者&#xff08;Builder&#xff09;&#xff1a;用于规范产品的各个组成部分&#xff0c;并进行抽象&…

U盘未格式化,数据恢复攻略大揭秘

U盘遭遇未格式化困境&#xff0c;数据安全岌岌可危 在日常的工作和生活中&#xff0c;U盘以其便携、容量大的特性成为了我们不可或缺的存储工具。然而&#xff0c;有时我们会遇到这样一个棘手的问题&#xff1a;当我们将U盘插入电脑时&#xff0c;却收到了“未格式化”的提示。…

Vue3新手教程

Vue3新手教程 一. Vue3简介1. 性能的提升2.源码的升级3. 拥抱TypeScript4. 新的特性 二. 创建Vue3工程1. 基于 vue-cli 创建2. 基于 vite 创建(推荐)3. 一个简单的效果 三. Vue3核心语法1. OptionsAPI 与 CompositionAPI2. 拉开序幕的 setup2.1 setup 概述2.2 setup 的返回值2.…

【LVGL-键盘部件,实体按键控制】

LVGL-二维码库 ■ LVGL-键盘部件■ 示例一&#xff1a;键盘弹窗提示■ 示例二&#xff1a;设置键盘模式■ 综合示例&#xff1a; ■ LVGL-实体按键控制■ 简介 ■ LVGL-键盘部件 ■ 示例一&#xff1a;键盘弹窗提示 lv_keyboard_set_popovers(kb,true);■ 示例二&#xff1a;设…

拿到今日现货白银价格 如何开始分析?

很多投资者看到近期现货白银的强劲涨势&#xff0c;并且开户入场。但入场之后&#xff0c;他们发现对如何找到机会还不甚了解。比方说我们拿到今日现货白银价格要如何开始分析呢&#xff0c;很多新入场的投资者根本没有头绪&#xff0c;下面我们就来讨论一下相关的方法。 我们可…

PyTorch 教程-快速上手指南

文章目录 PyTorch Quickstart1.处理数据2.创建模型3.优化模型参数4.保存模型5.加载模型 PyTorch 基础入门1.Tensors1.1初始化张量1.2张量的属性1.3张量运算1.3.1张量的索引和切片1.3.2张量的连接1.3.3算术运算1.3.4单元素张量转变为Python数值 1.4Tensor与NumPy的桥接1.4.1Tens…