wait和waitpid

news2024/10/24 23:16:40

在Linux中,waitwaitpid 是用于进程控制的系统调用,它们主要用来让父进程等待子进程的终止,并获取子进程的退出状态。下面详细介绍它们的用法和区别。

1. wait() 函数

wait() 会阻塞调用进程,直到一个子进程终止。它的典型用法如下:

函数原型

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);
  • 参数
    • status: 这是一个指向整数的指针,用来存储子进程的退出状态。如果不关心退出状态,可以传递 NULL
  • 返回值
    • 成功时,返回终止的子进程的 PID。
    • 失败时,返回 -1 并设置 errno

用法

int status;
pid_t pid = wait(&status);

if (pid == -1) {
    perror("wait");
} else {
    if (WIFEXITED(status)) {
        printf("Child exited with status %d\n", WEXITSTATUS(status));
    }
}

关键宏函数

status 是由子进程退出状态生成的,可以通过以下宏来检查子进程的退出原因:

  • WIFEXITED(status): 子进程是否正常退出。
  • WEXITSTATUS(status): 获取子进程的退出状态(当 WIFEXITED(status) 为真时使用)。
  • WIFSIGNALED(status): 子进程是否因为信号终止。
  • WTERMSIG(status): 获取导致子进程终止的信号。
  • WIFSTOPPED(status): 子进程是否处于暂停状态。
  • WSTOPSIG(status): 获取导致子进程暂停的信号。

特点

  • wait() 只会等待任意一个终止的子进程,并返回其 PID。
  • 如果有多个子进程,wait() 可能随机返回任意一个已终止的子进程,而不确定是哪一个。
  • wait() 在没有子进程时返回 -1 并设置 errnoECHILD

2. waitpid() 函数

waitpid() 提供了更强的灵活性,可以指定等待特定的子进程,也可以选择非阻塞模式。

函数原型

#include <sys/types.h>
#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *status, int options);
  • 参数

    • pid: 指定要等待的子进程的 PID,具体值可以为以下几种:
      • -1: 等待任意一个子进程(等价于 wait() 的行为)。
      • > 0: 等待特定的子进程,PID 为 pid 的子进程。
      • 0: 等待与调用进程在同一个进程组中的任意子进程。
      • < -1: 等待进程组 ID 为 |pid| 的任意子进程。
    • status: 和 wait() 类似,用来存储子进程的状态信息。
    • options: 控制行为的选项,常见的取值有:
      • 0: 阻塞等待,直到子进程终止。
      • WNOHANG: 非阻塞模式,如果没有子进程终止,waitpid() 返回 0
      • WUNTRACED: 还可以返回停止的子进程(收到 SIGSTOPSIGTSTP 等信号)。
  • 返回值

    • 成功时,返回子进程的 PID。
    • 如果使用 WNOHANG 且没有终止的子进程,返回 0
    • 失败时,返回 -1 并设置 errno

用法

int status;
pid_t pid = waitpid(-1, &status, 0); // 等待任意子进程

if (pid == -1) {
    perror("waitpid");
} else if (pid == 0) {
    // 当使用 WNOHANG 时,可以处理没有子进程退出的情况
    printf("No child has exited yet.\n");
} else {
    if (WIFEXITED(status)) {
        printf("Child exited with status %d\n", WEXITSTATUS(status));
    }
}

特点

  • waitpid()wait() 更灵活,可以指定等待特定的子进程。
  • 可以使用 WNOHANG 选项来避免阻塞。
  • waitpid() 支持等待子进程暂停的状态。

3. wait()waitpid() 的区别

功能wait()waitpid()
等待特定子进程不可以可以(通过 pid 参数)
阻塞/非阻塞模式只能阻塞支持非阻塞(通过 WNOHANG 选项)
等待任意子进程可以(默认行为)可以(通过 pid = -1
支持停止的子进程不支持支持(通过 WUNTRACED
等待同一进程组中的进程不支持可以(通过 pid = 0pid = -<pgid>

4. 总结

  • wait() 用于简单的父子进程同步,父进程等待任意一个子进程的退出。
  • waitpid() 提供更多控制,可以指定等待特定的子进程,并支持非阻塞模式和等待停止的子进程。
  • 它们主要用于进程管理和控制,是系统编程中非常重要的工具

 1:是什么

2:为什么也就是必要性

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

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

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

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

wait回收僵尸进程(父进程等待是必须的)(wait成功返回的是回收子进程的PI,失败返回-1)

运行后子进程的状态是S+,然后5秒后就会变成Z+(僵尸状态),然后再过5秒,父进程就会用wait给回收掉(wait是只能等待任意一个子进程)

变成Z

回收了

如果有多个子进程呢,wait等待哪一个呢

首先创建多个子进程,此代码的意思是,父进程进入for循环后,经过fork创建了一个子进程进入了RunChild,然后执行完RunChild后,exit(0),就退出子进程了,然后父进程再次进入循环,再次创建一个子进。。。。。。以此类推

一个wait等待任意一个,10个子进程要用循环了,wait回收僵尸进程(父进程等待是必须的,意思是需要等子进程结束后父进程再进行回收)(wait返回的是回收子进程的PID)

如果子进程一直不死,父进程就会一直等待也不返回,只要你退出了我才返回,这叫做阻塞等待

waitpid(可以保证最后结束的一定是父进程)

waitpid的单个进程总代码

这个waitpid(代码例子是单个子进程的)与wait(单个的进程用法一样)

status的使用,waitpid的第一个参数是自己的子进程,不能等待别人的子进程

子进程,一共有几种退出的场景

而不用全局变量,先在子进程改完,再从父进程中拿到,这是不可以的,因为进程具有独立性,所以要用wait等系统调用

查看子进程错误信息码,和exit返回的值        退出信号(signal)

另一种写法(这里的进程出异常是子进程出异常了,wait failed是父进程调取出异常了)

代码例子是多个子进程的waitpid用法,从父进程中获取exit(i)中多个i的值

 -1的情况总代码(没写)

非阻塞轮询(总代码没写)

这个第三个参数为0时就是默认是阻塞方式

举个例子:小张是操作系统,我是用户,我约着小张去学习,小张让我等他,我打电话催他就是系统调用的过程,打电话的本质就是问小张好了没,本质就是检查状态,小张说他好了或者没好,或者说还得等一会,这叫检查不成功,然后我把电话挂掉,这叫做系统调用立马返回,在这个过程中,我在不断不断的打电话询问,然后直接返回结果,立马挂断,叫做非阻塞,基于非阻塞然后一直给小张打电话(打电话不会被卡住),问他好了没有,这个过程就叫做轮询,所以非阻塞+循环就叫做非阻塞轮询。

然后第二天又约小张,因为有上次的教训,我就告诉小张,你不要挂电话,等你好的时候再说你好了,再挂电话,然后我一直抱着电话听他状态,这种就叫做纯阻塞式调用。(最常用够简单,父进程什么都做不了只能等待)

接着第三天, 又约他,变聪明了,一边打电话催,催完了,再自己玩自己的,在等他的过程中,也在做自己的事情,这就是非阻塞轮询+做自己的事情(这样就可以让父进程即在等待,又可以做自己的事情)

三种返回值结果:

这个第三个参数是非阻塞等待,是0就是阻塞等待

返回值有三种

记得加循环 

如果把第三个参数改成0就没有这种情况了,父进程就不可以做自己的事情了

用到了函数指针

ret==0的情况,父进程做自己的事代码(单进程版本,多进程的waitpid的第一个参数 改成-1就好):makefile中加上-std=c99,j就可以用int i=0;在for循环中了

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

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

相关文章

怎么ping网络ip地址通不通

怎么Ping网络IP地址通不通&#xff1f;要检查网络中的IP地址是否连通&#xff0c;可以使用‌Ping命令。Ping命令通过发送ICMP&#xff08;Internet Control Message Protocol&#xff0c;因特网控制消息协议&#xff09;Echo请求报文并等待回应&#xff0c;来判断目标主机是否可…

ARP限制网速攻击

ARP限制网速攻击 大家没想到吧&#xff0c;ARP还能限制对方网速。当kali欺骗了网关和受害者的时候&#xff0c;受害者访问网络就需要经过kali的网卡&#xff0c;那我们限制kali网卡的速度或者转发的速度就可以限制对方的网速。这里可以使用的工具有tc、iptables、WonderShaper…

Unix Standardization and Implementations

Unix标准化 在Unix未制定较为完备的标准时&#xff0c;各个平台的系统调用方式各异&#xff0c;所开发出的应用程序存在可移植性差的特点&#xff0c;因此人们呼吁指定一套Unix标准来规范接口&#xff0c;增加应用程序的可移植性。所谓Unix标准即适用于Unix环境下的一系列函数…

AI 时代技术盛宴 —— 稀土掘金 × 豆包 MarsCode 青训营等你来!

各位 CSDN 的小伙伴们&#xff0c;今天我要给大家带来一个超级棒的消息&#xff01;稀土掘金与豆包 MarsCode 强强联手&#xff0c;共同打造的青训营再次上线啦&#xff01; 在这个飞速发展的 AI 时代&#xff0c;这场青训营玩出了不一样的精彩。它携手 AI 伙伴豆包 MarsCode&…

一个项目用5款数据库?MySQL、PostgreSQL、ClickHouse、MongoDB区别,适用场景

文章目录 一、常用数据库概览1.1 关系型数据库1.2 非关系型数据库1.2.1 KV数据库1.2.2 文档型数据库1.2.3 列式存储数据库1.2.4 图数据库 1.3 SQL与NoSQL区别1.3.1 结构化与非结构化1.3.2 关联和非关联1.3.3 查询方式1.3.4 事务1.3.5 总结 二、MySQL三、PostgreSQL3.1 特点、适…

计组_中断响应条件

2024.10.13&#xff1a;计算机组成原理学习笔记 中断响应条件 条件1&#xff1a;CPU要处于开中断状态条件2&#xff1a;至少要有一个未被屏蔽的中断请求屏蔽&#xff1f;中断优先级屏蔽字的作用 条件3&#xff1a;当前指令刚执行完 条件1&#xff1a;CPU要处于开中断状态 当CP…

Redis:分布式 - 主从复制

Redis&#xff1a;分布式 - 主从复制 概念配置主从模式info replicationslave-read-onlytcp-nodelay 命令slaveof 主从结构一主一从一主多从 主从复制流程数据同步命令全量同步部分同步实时同步 节点晋升 概念 Redis的最佳应用&#xff0c;还是要在分布式系统中。对于非分布式…

如何解决 Vim 中的 “E212: Can‘t open file for writing“ 错误:从编辑到权限管理(sudo)

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

Squad战术小队开服教程

1、登录服务器&#xff08;百度莱卡云游戏面板&#xff09; 登录面板的信息在绿色的登陆面板按键下方&#xff0c;不是你的莱卡云账号 进入控制面板后会出现正在安装的界面&#xff0c;大约10分钟左右就能安装完成 2、设置 点击目录上的网络&#xff0c;你可以看到三个端口 然…

【Python】Twisted:让自定义网络应用开发变得简单

Twisted 是 Python 中一个成熟、功能强大的事件驱动网络编程框架。它支持多种协议&#xff0c;如 HTTP、FTP、SMTP 等&#xff0c;可以用于构建高性能的网络应用&#xff0c;包括网络服务器、客户端、代理服务器等。Twisted 的核心是基于事件驱动模型&#xff0c;能够有效处理大…

el-date-picker设置只有某些日期可选

示例图&#xff1a; <el-date-pickerv-model"topFormObj.upTime"type"date"value-format"timestamp"format"dd/MM/yyyy":picker-options"pickerOptions" /> 固定限制每周的周末周三不可选 data() {return {pickerOp…

Leetcode 乘积最大子数组

该算法的目的是求出一个整数数组中乘积最大的连续子数组。 算法思想&#xff1a; 问题分析&#xff1a; 我们需要在数组中找到连续的子数组&#xff0c;使得该子数组的乘积最大。这个问题类似于“最大子序和”&#xff0c;但乘积相比求和有更多的复杂性&#xff0c;特别是当数…

销售管理的五大职能

什么是销售管理 销售管理&#xff0c;这一看似简单的概念&#xff0c;实则蕴含着丰富的内涵与细致的操作。它不仅仅是对销售团队的监督和对客户满意度的追求&#xff0c;更是通过一系列策略和手段&#xff0c;优化销售流程&#xff0c;提升业务成果的过程。 销售管理的内核 …

electron本地OCR实现

使用tesseract.js - npm (npmjs.com) 官方demo&#xff1a;GitHub - Balearica/tesseract.js-electron: An example to use tesseract.js in electron 目录结构&#xff1a; async function ocr() {const worker await Tesseract.createWorker("chi_sim", 1, {wor…

前端打印功能(vue +springboot)

后端 后端依赖生成pdf的方法pdf转图片使用(用的打印模版是带参数的 ,参数是aaa)总结 前端页面 效果 后端 依赖 依赖 一个是用模版生成对应的pdf,一个是用来将pdf转成图片需要的 <!--打印的--><dependency><groupId>net.sf.jasperreports</groupId>&l…

探索 YOLO11:更快、更智能、更高效

点击下方卡片&#xff0c;关注“小白玩转Python”公众号 在人工智能这个不断进化的世界中&#xff0c;有一件事我们可以肯定&#xff1a;模型不断变得更好、更快、更智能。就在你以为 YOLO 系列已经达到顶峰时&#xff0c;Ultralytics 推出了最新升级——YOLO11。没错&#xff…

K-means 聚类算法:目标函数推导、迭代过程及可视化解析

一、K-means 的背景 在机器学习领域&#xff0c;许多任务涉及 训练模型来做预测或分类 。比如&#xff0c;医生可能希望通过以往的病例数据来预测某个病人未来是否会患上某种疾病&#xff0c;或者新闻网站可能需要根据文章的主题将新闻自动分类。这些任务通常依赖于有标签的数…

Qt之TCP收发图片的例子

一.效果 二.实现 1.发图片 void MainWindow::slotSendImage() {matrix.rotate(90);QPixmap tempPixmap = pixmap.transformed(matrix);QBuffer buffer;tempPixmap.save(&buffer,"jpg");ui->labelImage->setPixmap(tempPixmap);int dataLength = buffer.d…

UE4 材质学习笔记09(雨水水坑着色器/完整雨水着色器)

一.雨水水坑着色器 要用到这样一个噪声贴图&#xff0c;我们要做的就是&#xff0c;做出水坑并让水坑在这种浑浊的噪点中产生&#xff0c;因此水坑将从最暗的斑点生长&#xff0c;然后随着它继续占据越来越亮的像素而生长 现在水坑将从上到下投射到世界空间中&#xff0c;所以…

C++:模拟priority_queue

目录 priority_queue的介绍 概念 特点 priority_queue的使用 基本操作 演示代码 ​编辑 priority_queue的模拟实现 仿函数 向上调整和向下调整 模拟实现的代码 priority_queue的介绍 概念 在C标准库中&#xff0c;priority_queue是一个基于优先级堆的容器适配器。…