进程等待

news2024/11/25 21:36:34

文章目录

  • 一、进程的结果
  • 二、进程等待

一、进程的结果

在现实生活中找别人帮忙办事,别人同意帮忙之后,会反馈给自己的结果无非就是三种:

  1. 别人把事办完了,结果是自己想要的
  2. 别人把事办完了,由于办事的方法错误,导致结果并不是自己想要的
  3. 别人办事时遇到阻碍了,没办法继续完成这件事情

同样的,进程创建出来也是用来帮忙做事的,进程运行完成后,进程的结果有三种情况:

  • 进程运行正常,结果正确
  • 进程运行正常,结果错误
  • 进程运行异常

对于进程运行正常而言,我们可以通过进程的退出码,来判断进程的运行结果是否正常

进程可以通过 main 函数中 return int 或者 任意代码处调用的 exit(int) 函数 正常退出,其中 return 返回的值和 exit 函数的参数,即为进程的退出码

echo $? 可以查看最近一次运行的程序的退出码

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    // 计算
    printf("begin ...\n");
    int sum = 0;
    for (int i = 1; i <= 100; ++i) sum += i;
    sleep(1);
    printf("end, result: %d\n", sum);

    exit(11);  // 或者 return 11 表示运行正常,结果错误
    // return 0; // 或者 exit(0) 表示运行正常,结果正确
}

进程的退出码为 0 表示结果正确
在这里插入图片描述

进程的退出码非 0 表示结果错误
在这里插入图片描述

打印错误码对应的错误信息

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    for (int i = 0; i < 255; ++i)
        printf("errno %d : %s\n", i, strerror(i));
    
    return 0;
}

这里只截取了一部分,感兴趣的读者可以自行运行查看
在这里插入图片描述

系统调用 _exit(int) 也可以结束进程,与库函数 exit(int) 的关系是:库函数 exit(int) 会先进行关闭文件流,冲刷缓冲区等操作,然后再调用 _exit(int) 结束进程

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    printf("hello world");

    // 系统调用 _exit(int) 不会关闭文件流,冲刷缓冲区等,直接结束进程
    _exit(0);

    // 库函数 exit(int) 会关闭文件流,冲刷缓冲区等,在结束进程
    // exit(0);
}

exit(int) 函数会冲刷缓冲区,所以打印了 hello world
在这里插入图片描述

_exit(int) 函数直接结束进程,不会打印 hello world
在这里插入图片描述

对于进程运行异常,是由于进程收到了操作系统的信号,参考

二、进程等待

当子进程先于父进程退出时,子进程会处于僵尸状态,为了回收子进程的资源,防止内存泄漏,以及可以选择性的接收子进程的结果,父进程需要等待子进程

系统调用 wait / waitpid,头文件 sys/types.h 和 sys/wait.h

  • pid_t wait(int* status),阻塞式等待任意一个子进程(如果没有子进程退出,父进程会阻塞在 wait 函数)

返回值:等待成功返回子进程的 pid,出错返回 -1,并且 errno 被设置为相应的出错信息

参数:status 为输出型参数,用于存储子进程的退出码,如果不关心子进程的退出码,可以设置为 NULL

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

int main()
{
    // 创建子进程
    pid_t id = fork();
    assert(id != -1);
    if (id == 0)
    {
        // 子进程
        int cnt = 5;
        while (cnt)
        {
            printf("我是子进程,我的 pid 是: %d,我的 ppid 是: %d\n我还剩余 %d s\n", getpid(), getppid(), cnt--);
            sleep(1);
        }

        exit(0);
    }
    
	// slepp(10); 模拟父进程的任务

    // 等待子进程
    printf("我是父进程,我的 pid 是: %d, 开始等待子进程 %d ...\n", getpid(), id);
    pid_t cid = wait(NULL);
    assert(cid != -1);
    printf("我是父进程,我的 pid 是: %d, 等待子进程 %d 成功\n", getpid(), cid);

    return 0; 
}

父进程阻塞在 wait 函数处
在这里插入图片描述

加上 sleep(10) 之后,子进程会先进入僵尸状态,父进程调用 wait 回收资源后,子进程的僵尸状态随之消失
在这里插入图片描述

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

返回值:等待成功返回子进程的 pid,出错返回 -1

参数:

  • pid 如果设置为 -1,表示等待任意一个子进程,pid 如果大于 0,则表示等待指定 pid 的子进程
  • status 为输出型参数,用于存储子进程的退出码,如果不关心子进程的退出码,可以设置为 NULL
  • options 如果设置为 0,表示阻塞式等待,如果设置为 WNOHANG,则表示非阻塞等待(调用时子进程还未退出,waitpid 函数会返回 0)

进程的结果有三种情况,整数 status 是采用如下位图的方式来存储进程的结果

  • 正常终止:0 ~ 7 位为 0,8 ~ 15 位表示退出码

  • 异常终止:0 ~ 6 位表示收到的信号,第 7 位表示是否为核心转储,8 ~ 15 位没有使用
    在这里插入图片描述

  • 宏 WIFEXITED(status),用于判断 status 是否收到信号,即子进程是否运行正常

  • 宏 WEXITSTATUS(status),当子进程运行正常时,用于获取子进程的退出码

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

int main()
{
    pid_t id = fork();
    assert(id != -1);
    if (id == 0)
    {
        // 子进程
        int cnt = 5;
        while (cnt)
        {
            printf("我是子进程,我的 pid 是: %d,我的 ppid 是: %d,我还剩余 %ds\n", getpid(), getppid(), cnt--);
            sleep(1);
        }

        exit(0);
    }
    
    // 父进程
    int status = 0;
    while (1)
    {
        pid_t ret_id = waitpid(id, &status, WNOHANG);
        assert(ret_id != -1);
        if (ret_id > 0)
        {
            // 等待成功
            printf("我是父进程,我的 pid 是: %d,等待子进程 %d 成功\n", getpid(), ret_id);

            // 判断是否是信号导致
            if (WIFEXITED(status))
                printf("子进程 %d 运行正常,退出码: %d\n", ret_id, WEXITSTATUS(status));
            else 
                printf("子进程 %d 运行异常", ret_id);

            break;
        }

        // 父进程的任务
        printf("我是父进程,我的 pid 是: %d, 正在执行任务中 ...\n", getpid());
        sleep(1);
    }

    return 0;
}

父进程非阻塞等待,子进程进入僵尸状态,父进程调用 waitpid 回收资源后,子进程的僵尸状态随之消失
在这里插入图片描述

wait / waitpid 是如何得到子进程的结果呢?其实就是通过子进程的 task_struct 中的属性得到的

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

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

相关文章

利用代理ip实现自动化爬虫任务管理

我们在进行爬虫任务管理时&#xff0c;需要对爬取目标、爬取频率、数据存储等多个方面进行规划和管理。使用HTTP代理可以帮助我们提高爬虫效率&#xff0c;同时也可以实现自动化的爬虫任务管理。下面我们来分析一下怎么利用代理ip实现自动化爬虫任务管理。 一、选择代…

Server - 配置 Kubeflow Notebooks 的 JupiterLab 环境

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/131231501 Kubeflow 的 Notebook 功能是一种方便的方式&#xff0c;让用户可以在 Kubernete s集群上创建和管理交互式的 Jupyter Notebo…

招生 | 北京大学—知识图谱能力提升培训

北京大学继续教育项目 《北京大学—知识图谱能力提升培训班》 招生简章 培训安排 &#xff08;一&#xff09;培训时间 上课时间&#xff1a;2023年7月15日—7月17日 上课方式&#xff1a;在北京大学燕园校区&#xff08;校本部&#xff09;线下集中授课 &#xff08;二&a…

科技云报道:大模型时代,AI基础软件机会何在?

科技云报道原创。 大模型时代&#xff0c;离不开算力&#xff0c;算法、数据的喂养。如果将视角放至整个产业链上&#xff0c;算法背后&#xff0c;还有一个关键要素值得被关注&#xff0c;那就是AI基础软件。 算法是实现AI功能的关键&#xff0c;而基础软件则为算法提供运行…

【Unity】代码控制视频的播放(视频播放器-更新)

结果如上图&#xff0c;之前写过一个使用代码控制视频播放器的Demo&#xff0c;但是好多小伙伴说我附带的链接没法下载&#xff0c;这次我直接做一个完整版的&#xff0c;不用下载&#xff0c;照着一步一步做就能做出来。 之前写了如何设置RawImage进行自动播放&#xff0c;大…

movetoThread应用的注意点

分析 官网的说明&#xff1a; void QObject::moveToThread(QThread *targetThread) Changes the thread affinity for this object and its children. The object cannot be moved if it has a parent. Event processing will continue in the targetThread. To move an objec…

流动微管反应器的精密压力控制解决方案

摘要&#xff1a;针对目前连续流反应器或微反应器压力控制中存在手动背压阀控制不准确、电动或气动背压阀响应速度太慢、无法适应不同压力控制范围和控制精度要求、以及耐腐蚀和耐摩擦性能较差等诸多问题&#xff0c;本文提出了相应的解决方案。解决方案的核心是分别采用了低压…

装配式从上世纪就开始了?到现在与BIM还干了这件大事!

​大家好&#xff0c;这里是建模助手。 说起装配式&#xff0c;相信各位都不会陌生。在我国传统建筑业资源浪费率高、污染重而饱受诟病的背景下&#xff0c;施工污染少、建造速度快、资源利用率高的装配式越来越受社会关注。 除了一些常规化的特点&#xff0c;如&#xff1a;…

4.2.2 基础指令的操作

显示日期与时间的指令&#xff1a; date 显示日历的指令&#xff1a; cal 简单好用的计算机&#xff1a; bc 1. 显示日期的指令&#xff1a; date 如果在命令行中想要知道目前Linux系统的时间&#xff0c;那么就直接在命令行界面输入date即可显示&#xff1a; [dmtsaistud…

小程序开发的优点和挑战:全面解析

小程序开发的优点是什么&#xff1f; 对于许多人来说&#xff0c;小程序的出现并没有给他们带来太多惊喜。然而&#xff0c;在过去的几年里&#xff0c;微信一直在努力成为更具影响力的社交平台&#xff0c;并且对于小程序开发的需求也在不断增加。随着小程序应用程序在其生态…

Spring Boot 属性加载原理解析

基于Spring Boot 3.1.0 系列文章 Spring Boot 源码阅读初始化环境搭建Spring Boot 框架整体启动流程详解Spring Boot 系统初始化器详解Spring Boot 监听器详解Spring Boot banner详解Spring Boot 属性配置解析Spring Boot 属性加载原理解析 在《Spring Boot 框架整体启动流程详…

MAYA柔体与弹簧一起使用 6个例子

例子2 Q弹 隐藏物体设置移动动画 例子 3 柔体和粒子 例子4 坑的反弹 例子5 例子6

021+limou+C语言内存管理

0.在Linux下验证C语言地址空间排布 这里是limou3434的博文系列。接下来&#xff0c;我会带您了解在C语言程序视角下的内存分布&#xff0c;会涉及到一点操作系统的知识&#xff0c;但是不多&#xff0c;您无需担忧。 注意&#xff1a;只能在Linux下验证&#xff0c;因为Windo…

如何在客户验收环节搞垮一个项目,大佬是有一套方法的

通过产品、UI、开发、测试撸起袖子加油干&#xff0c;经历需求、设计、研发、测试层层关卡终于进入到了期待已久的客户验收环节。在项目的尾声&#xff0c;连空气里都充满了快活的气氛。 而励志要搞垮项目的大佬心里就不爽了“小样儿&#xff0c;你们认为你们就赢了吗&#xf…

Nginx的安装和配置

下载 访问官网&#xff1a;https://nginx.org/ 点击最新的版本下载&#xff0c; 进入详情页&#xff0c;选择下载任意版本 解压编译安装 tar zxvf nginx-1.22.1.tar.gz解压之后得到文件夹 nginx-1.22 安装之前保证使用的工具和库存在 # 安装gcc yum install -y gcc # 安装…

STM32开发——串口通讯(第2篇)——WIFI(Esp8266)

目录 1.ESP8266 作为设备 2.ESP8266作为服务器 注意&#xff1a;1.在中断中一般不直接在中断服务函数里处理数据&#xff0c;而是在收到数据后直接丢给队列&#xff0c;再处理数据&#xff1b; 2.在中断服务函数里尽量减少使用延时函数及打印函数。 1.ESP8266 作为设备 1.1…

mongo副本集的一些操作

开启副本集 修改配置文件/etc/mongod.conf replication:replSetName: main重启mongod相关服务systemctl restart mongod 注意:每个在副本集中的成员&#xff0c;无论主副replSetName都一样&#xff0c;表示一个副本集的名称 如果添加的节点的replSetName和主节点不一致&…

退出卸载企业奇安信360

一般退出&卸载企业奇安信需要密码&#xff0c;然后我们又都不知道密码是多少的情况下怎么退出奇安信呢 1.打开奇安信的设置 2.找到 "防护中心"--"自我保护" 然后点击确定 3.找到奇安信的安装目录 找到"D:\奇安信\360Safe\EntClient\conf"下面…

python带你获取TripAdvisor旅游景点的真实评价

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 猫途鹰&#xff08;TripAdvisor&#xff09;是一个旅游点评网站&#xff0c; 如果您想要爬取该网站的数据&#xff0c;需要了解该网站的访问规则和爬取限制。 所使用软件工具&#xff1a; python 3.8 运行代码 pycha…

【PTA】温故知新模拟题

目录 L1-2 日期格式化 输入格式&#xff1a; 输出格式&#xff1a; 输入样例&#xff1a; 输出样例&#xff1a; 代码&#xff1a; L1-4 心理阴影面积 输入格式&#xff1a; 输出格式&#xff1a; 输入样例&#xff1a; 输出样例&#xff1a; 代码&#xff1a; 7-3…