进程控制相关

进程终止

        进程终止时,操作系统要释放对应进程申请的相关内核数据结构和对应的代码和数据。其不本质就是释放进程申请的系统资源。

进程终止的常见方式:

1、代码运行完毕且结果正确。

2、代码运行完毕但结果不正确。

3、代码没运行完,进程异常退出。

        main函数的返回值是进程的退出码,如果为0,表示运行结果是正确的,如果非零,标识的是运行结果不正确。进程退出码用来返回给上一级进程,用来评判该进程的执行结果,另外,如果进程退出码是非零的,不同的非零值可以标识不同的错误原因,便于定位错误原因。通常使用stderror(errno)以字符串形式来输出具体错误原因。

进程等待

        子进程退出时,如果父进程不管子进程,那么子进程就处于僵尸状态,会导致系统资源层面的内存泄漏问题。另外,父进程创建子进程,是为了完成某种任务,那么父进程就可能要关心子进程将该任务完成的怎么样,因此需要等待子进程退出。

具体系统接口:

wait函数和waitpid函数的返回值:

        wait函数等待子进程成功就会返回子进程的pid,如果失败,就会返回-1。 如果设置了status参数,那么对status进行设置,将进程的具体状态设置进去。

waitpid函数参数

        pid_t pid:可以有四种状态,当pid = -1时,代表等待任意一个子进程退出,当pid > 0时,会等待对应子进程识别码为pid的子进程退出,当pid < -1时,等待进程组识别码为pid绝对值的任何子进程,当pid = 0时,等待进程组识别码为pid的子进程。

        options: 0表示阻塞等待,如果没有等到子进程退出,就会一直阻塞等待,WNOHANG表示非阻塞等待。

        status:wait和waitpid函数会把被等待进程的退出状态信息记录到status中。另外,如果进程异常退出,那么此时的进程退出码是没有意义的。

status的构成

        status并不是按照整数来整体使用的,而是按照比特位的方式,将32个比特位进行划分,这里只关心低七位和次低八位。

        最低的7个比特位用来表示进程收到的信号,次低八位用来表示进程退出码。

具体例子:

#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>
#include<stdlib.h>
int code = 0;
int main()
{
    pid_t id = fork();
    if (id < 0)
    {
        //创建子进程失败
        perror("fork");
        exit(1);//不正常退出
    }
    else if (id == 0)
    {
        //child process
        int cnt = 5;
        while (cnt)
        {
            printf("cnt: %d, 我是子进程, pid: %d, ppid : %d\n", cnt, getpid(), getppid());
            sleep(1);
            cnt--;                                                   
        }
        code = 15;
        exit(15);
    }
    else
    {
        //parent process
        printf("我是父进程, pid: %d, ppid: %d\n", getpid(), getppid());
        int status = 0;
        pid_t ret = waitpid(id, &status, 0); //阻塞式的等待!
        if (ret > 0)
        {
            //0x7F -> 00000..1111111低七位表示退出信号
            //次低八位表示退出信号
            printf("等待子进程成功,ret: %d, 子进程信号编号:%d,子进程退出码%d\n", ret, status & 0x7F, (status >> 8) & 0xFF);
        }
    }
}

        因为进程异常退出时,所得到的进程退出码是无意义的,所以一般只有在进程正常退出时,才去关心进程的退出码。Linux中提供了对应的宏,不用每次手动提取。

WIFEXITED:若为正常终止的子进程返回的状态,则为真(查看进程是否正常退出)
WEXITSTATUS:若WIFEXITED非零,提取子进程退出码(查看进程退出码)

具体例子:

#include<sys/wait.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int status = 0;
int main()
{
    pid_t id = fork();
    if(id < 0)
    {
        perror("fork");
        exit(-1);
    }
    else if(id > 0)
    {
        //child process
        
    }
    else
    {
       //parent process
       pid_t ret =  waitpid(id, &status, 0);
       if(WIFEXITED(status))//退出信号
       {
           //子进程正常退出
           printf("子进程执行完毕,退出码:%d\n", WEXITSTATUS(status));

       }
       else
       {
           printf("子进程异常退出:%d\n", WIFEXITED(status));
       } 
    }
    return 0;
}

进程程序替换

        fork()之后,父子进程各自执行进程代码的一部分,但如果子进程想执行一个全新的程序,就要通过进程程序替换,通过特定的接口,加载磁盘上的一个全新的程序(代码+数据),加载到调用进程的地址空间中。其本质是将新的磁盘上的程序上的程序加载到内存,并和当前进程的页表重新建立映射的过程。

        进程替换并没有创建新的子进程,只是改变了对应的映射关系。

具体的exec接口系列:

 具体例子:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int status = 0;
int main()
{
    pid_t id = fork();
    if(id < 0)
    {
        perror("fork");
       _exit(1);//系统接口不会刷新缓冲区
    }
    else if(id > 0)
    {
        //parent process
        printf("我是父进程\n");
    }
    else
    {
        //child process
        printf("我是子进程\n");
        execlp("python", "python", "test.py", NULL);
        fflush(stdout);
        pid_t ret = waitpid(id, &status, 0);
        if(WIFEXITED(status))//退出信号
        {
                       //子进程正常退出
            printf("子进程执行完毕,退出码:%d\n", WEXITSTATUS(status));                            
        }
        else
        {
            printf("子进程异常退出:%d\n", WIFEXITED(status));
                                     
        }
        printf("我是子进程");    
    }

    return 0;
}

        细节:execl系列的接口是程序替换,调用该函数成功后,会将当前进程的所有代码和数据都进行替换,包括已经执行的和没有执行的。所以一旦调用成功,后续所有代码都不会被执行。

为何需要创建子进程的原因:

        结合进程替换,如果不创建子进程,那么在进程替换时只能替换父进程。创建子进程之后,替换的就是子进程,而不影响父进程。因为父进程一般聚焦于读取数据,解析数据,指派执行代码的功能。

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

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

相关文章

【Entity Framework】闲话EF中批量配置

【Entity Framework】闲话EF中批量配置 文章目录 【Entity Framework】闲话EF中批量配置一、概述二、OnModelCreating中的批量配置元数据API的缺点 三、预先约定配置忽略类型默认类型映射预先约定配置的限制约定添加新约定替换现有约定约定实现注意事项 四、何时使用每种方法进…

通过实例学C#之ArrayList

介绍 ArrayList对象可以容纳若干个具有相同类型的对象&#xff0c;那有人说&#xff0c;这和数组有什么区别呢。其区别大概可以分为以下几点&#xff1a; 1.数组效率较高&#xff0c;但其容量固定&#xff0c;而且没办法动态改变。 2.ArrayList容量可以动态增长&#xff0c;但…

使用go和消息队列优化投票功能

文章目录 1、优化方案与主要实现代码1.1、原系统的技术架构1.2、新系统的技术架构1.3、查看和投票接口实现1.4、数据入库MySQL协程实现1.5、路由配置1.6、启动程序入口实现 2、压测结果2.1、设置Jmeter线程组2.2、Jmeter聚合报告结果&#xff0c;支持11240/秒吞吐量2.3、Jmeter…

vue 一键更换主题颜色

这里提供简单的实现步骤&#xff0c;具体看自己怎么加到项目中 我展示的是vue2 vue3同理 在 App.vue 添加 入口处直接修改 #app { // 定义的全局修改颜色变量--themeColor:#008cff; } // 组件某些背景颜色需要跟着一起改变&#xff0c;其他也是同理 /deep/ .ant-btn-primar…

『FPGA通信接口』汇总目录

Welcome 大家好&#xff0c;欢迎来到瑾芳玉洁的博客&#xff01; &#x1f611;励志开源分享诗和代码&#xff0c;三餐却无汤&#xff0c;顿顿都被噎。 &#x1f62d;有幸结识那个值得被认真、被珍惜、被捧在手掌心的女孩&#xff0c;不出意外被敷衍、被唾弃、被埋在了垃圾堆。…

【Linux学习】Linux编辑器-vim使用

这里写目录标题 1. &#x1f320;vim的基本概念&#x1f320;2. vim的基本操作&#x1f320;3.vim异常处理&#x1f320;4. vim正常模式的相关命令&#x1f320;5. vim末&#xff08;底&#xff09;行模式相关命令 vi/vim都是多模式编辑器&#xff0c;不同的是vim是vi的升级版本…

开发与产品的战争之自动播放视频

开发与产品的战争之自动播放视频 起因 产品提了个需求&#xff0c;对于网站上的宣传视频&#xff0c;进入页面就自动播放。但是基于我对chromium内核的一些浅薄了解&#xff0c;我当时就给拒绝了: “浏览器不允许”。&#xff08;后续我们浏览器默认都是chromium内核的&#…

2024年华中杯数模竞赛A题完整解析(附代码)

2024年华中杯数模竞赛A题 基于动态优化的太阳能路灯光伏板朝向以最大化能量收集研究摘要问题重述问题分析模型假设符号说明 代码问题一 完整资料获取 基于动态优化的太阳能路灯光伏板朝向以最大化能量收集研究 摘要 随着可再生能源技术的发展&#xff0c;太阳能作为一种清洁的…

C++类与对象(中)②

目录 1.赋值运算符重载 1.1运算符重载 1.2赋值运算符重载 1.2.1赋值运算符重载格式 1.2.2赋值运算符只能重载成成员函数不能重载成全局函数 1.2.3同拷贝函数一样&#xff0c;如果类是形如日期类这样变量全是内置类型的&#xff0c;赋值运算符就必须自己实现&#xff0c;…

Spectre-v1 简介以及对应解决措施

文章目录 前言一、Variant 1: Exploiting Conditional Branches.二、 BACKGROUND2.1 Out-of-order Execution2.2 Speculative Execution2.3 Branch Prediction2.4 The Memory Hierarchy2.5 Microarchitectural Side-Channel Attacks2.6 Return-Oriented Programming 三、 ATTAC…

大学生简历大赛演讲稿(6篇)

大学生简历大赛演讲稿&#xff08;6篇&#xff09; 以下是六篇大学生简历大赛演讲稿的范文&#xff0c;供您参考&#xff1a; 范文一&#xff1a;展现真我&#xff0c;点亮未来 尊敬的评委、亲爱的同学们&#xff1a; 大家好&#xff01; 今天&#xff0c;我站在这里&#xf…

区块链实验室(35) - 编译solana for ARM64版

今天终于成功编译solana for arm64版&#xff0c;编译时间巨长。见下图所示。编译步骤详见solana网站https://github.com/solana-labs/solana和https://docs.solanalabs.com/。

【C语言】【数据结构】项目实践——贪吃蛇游戏(超详细)

前言 本篇博客我们来实现一个小游戏项目——贪吃蛇&#xff0c;相信肯定很多人都玩过&#xff0c;那么整个贪吃蛇是怎么实现出来的那&#xff0c;这个项目用到了很多方面的知识&#xff1a;C语言函数、枚举、结构体、动态内存管理、预处理指令、链表、Win32 API等。我们就通过这…

nodejs工具模块学习

util 是一个Node.js 核心模块&#xff0c;提供常用函数的集合&#xff1b; util.inspect(object,[showHidden],[depth],[colors]) 是一个将任意对象转换 为字符串的方法&#xff0c;通常用于调试和错误输出&#xff1b; 如果只有一个参数 object&#xff0c;是要转换的对象&…

网工内推 | 兴业银行总行正编,科技运维部,硕士以上学历

01 兴业银行 招聘岗位&#xff1a;安全渗透专家 职责描述&#xff1a; 1.负责牵头组织本行红蓝对抗、攻防演练等工作&#xff1b; 2.负责牵头制定有效的渗透测试方案&#xff0c;开展对本行防御体系的验证工作&#xff1b; 3.负责牵头组织本行各类应用系统的渗透测试与漏洞扫…

java的Spring XML和注解解析深入理解

正文 熟悉IOC体系结构 要学习Spring源码&#xff0c;我们首先得要找准入口&#xff0c;那这个入口怎么找呢&#xff1f;我们不妨先思考一下&#xff0c;在Spring项目启动时&#xff0c;Spring做了哪些事情。这里我以最原始的xml配置方式来分析&#xff0c;那么在项目启动时&a…

大型网站系统架构演化实例_5.使用反向代理和CDN加速网站响应

1.使用反向代理和CDN加速网站响应 随着网站业务不断发展&#xff0c;用户规模越来越大&#xff0c;由于区域的差别使得网络环境异常复杂&#xff0c;不同地区的用户访问网站时&#xff0c;速度差别也极大。有研究表明&#xff0c;网站访问延迟和用户流失率正相关&#xff0c;网…

二叉检索树(定义、意义、存储数据元素形式),二叉检索树插入方法的图解和实现

1、二叉检索树&#xff1a; &#xff08;1&#xff09;定义 二叉检索树的任意一个结点&#xff0c;设其值为k&#xff0c;则该节点左子树中任意一个结点的值都小于k&#xff1b;该节点右子树中任意一个节点的值都大于或等于k 这里的比较规则可以是针对数字的&#xff0c;也可…

js实现抽奖效果

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>随机抽奖</title> </head> <body>…

synchronized锁升级原理

锁升级过程 jdk1.6之后的优化 synchronized锁有四种状态&#xff0c;无锁&#xff0c;偏向锁&#xff0c;轻量级锁&#xff0c;重量级锁&#xff0c;这几个状态会随着竞争状态逐渐升级&#xff0c;锁可以升级但不能降级&#xff0c;但是偏向锁状态可以被重置为无锁状态。 1、偏…