使用 `fork()` 和 `waitpid()` 进行进程管理的详解

news/2024/10/15 21:39:55/

使用 fork()waitpid() 进行进程管理的详解

在 C/C++ 编程中,fork()waitpid() 是处理进程创建和管理的关键函数。本文将深入探讨 fork() 的用法、参数解析、wait()waitpid() 的区别,以及如何正确获取子进程的退出状态。

1. fork() 函数概述

fork() 函数用于创建一个新进程。它的声明如下:

#include <unistd.h>pid_t fork(void);

返回值

  • 进程:返回新创建的子进程进程ID(PID)。
  • 进程:返回 0。
  • 失败:返回 -1,并设置 errno

2. fork() 的基本用法

示例代码

以下示例演示如何使用 fork() 创建一个子进程

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>int main() {pid_t pid = fork();if (pid < 0) {// fork失败perror("fork failed");exit(1);} else if (pid == 0) {// 子进程printf("I am the child process with PID: %d\n", getpid());exit(0);  // 子进程正常退出} else {// 父进程printf("I am the parent process with PID: %d, and I created a child with PID: %d\n", getpid(), pid);}return 0;
}

代码解析

  • 创建子进程:调用 fork()
  • 错误处理:检查 fork() 的返回值,判断创建子进程是否成功。
  • 进程逻辑:如果返回 0,打印子进程的 PID 并退出。
  • 进程逻辑:如果返回值大于 0,打印父进程及子进程的 PID。

3. 进程状态的获取

当子进程结束后,父进程需要获取其退出状态。可以通过 wait()waitpid() 函数来实现。

3.1 wait() 函数

wait() 的声明如下:

#include <sys/wait.h>pid_t wait(int *status);
  • 参数status 是指向整数的指针,wait() 将子进程的退出状态存储在这里。
  • 返回值:返回结束的子进程的 PID,若没有子进程则返回 -1。

示例代码

以下示例展示了如何使用 wait() 来获取子进程的状态:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>int main() {pid_t pid = fork();if (pid < 0) {perror("fork failed");exit(1);} else if (pid == 0) {// 子进程printf("Child process with PID: %d is running...\n", getpid());sleep(2);  // 模拟工作exit(42);  // 子进程以状态 42 退出} else {// 父进程int status;pid_t wpid = wait(&status);  // 等待子进程结束if (wpid == -1) {perror("wait failed");exit(1);}// 解析退出状态if (WIFEXITED(status)) {printf("Child process %d exited with status %d\n", wpid, WEXITSTATUS(status));} else {printf("Child process %d did not terminate normally\n", wpid);}}return 0;
}

3.2 waitpid() 函数

waitpid() 函数用于等待特定子进程的状态变化,其声明如下:

#include <sys/wait.h>pid_t waitpid(pid_t pid, int *status, int options);
  • 参数
    • pid:要等待的子进程的 PID。可以为:
    • status:指向整数的指针,用于存储子进程的退出状态。
    • options:通常为 0,或使用一些选项标志。

示例代码

以下示例展示了如何使用 waitpid() 来获取特定子进程的状态:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>int main() {pid_t pid = fork();if (pid < 0) {perror("fork failed");exit(1);} else if (pid == 0) {// 子进程printf("Child process with PID: %d is running...\n", getpid());sleep(2);  // 模拟工作exit(42);  // 子进程以状态 42 退出} else {// 父进程int status;pid_t wpid = waitpid(pid, &status, 0);  // 等待指定子进程结束if (wpid == -1) {perror("waitpid failed");exit(1);}// 解析退出状态if (WIFEXITED(status)) {printf("Child process %d exited with status %d\n", wpid, WEXITSTATUS(status));} else {printf("Child process %d did not terminate normally\n", wpid);}}return 0;
}

4. wait()waitpid() 的区别

特性wait()waitpid()
等待的进程等待任意子进程可以指定等待特定的子进程
返回值返回任何结束的子进程的 PID返回指定的子进程的 PID
选项不支持选项支持选项参数,可以控制行为
灵活性相对较低相对较高

使用场景

  • wait():适合于简单的情况,只需等待任意子进程结束时使用。
  • waitpid():适合于需要等待特定子进程或进行更复杂的进程管理时使用。

5. 进程状态的解析

在处理子进程的退出状态时,通常会用到以下宏:

  • WIFEXITED(status):如果子进程正常退出,返回非零值。
  • WEXITSTATUS(status):返回子进程的退出状态,需在 WIFEXITED 返回真时使用。
  • WIFSIGNALED(status):如果子进程是因为信号而终止,返回非零值。
  • WTERMSIG(status):返回导致子进程终止的信号编号。

示例状态解析

if (WIFEXITED(status)) {printf("Child exited with status: %d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {printf("Child terminated by signal: %d\n", WTERMSIG(status));
}

6. 总结

fork()wait()waitpid() 是 UNIX/Linux 系统中管理进程的基础工具。通过理解它们的用法及区别,程序员可以有效地创建和管理进程的生命周期,避免僵尸进程的出现。

在使用 fork() 和等待子进程的状态时,请注意以下几点:

  • fork() 创建的子进程是父进程的副本,但它们是独立的进程
  • 正确处理 fork() 的返回值,以区分父进程和子进程
  • 使用 wait()waitpid() 处理子进程的结束状态,以防止产生僵尸进程

http://www.ppmy.cn/news/1539626.html

相关文章

单链表算法题(一)(超详细版)

前言 : 通过算法题 &#xff0c; 学习解决问题的思路 &#xff0c; 再面对类似的算法题时 &#xff0c; 能快速定位解决方案 一 . 移除链表元素 移除链表元素 : . - 力扣&#xff08;LeetCode&#xff09; 思路一 &#xff1a; 通过遍历链表找到值为val 的结点 &#xff0c; …

应急响应:DHCP$DNS劫持实战

目录 DHCP DHCP安全性&#xff1a; DHCP常见的攻击手段&#xff1a; DNS DNS常见的攻击方式&#xff1a; DNS&DHCP攻击实战演练&#xff1a; 环境配置&#xff1a; 利用&#xff1a; 排查&#xff1a; 防御&#xff1a; DHCP 介绍&#xff1a; DHCP&#xff08;…

【代码随想录Day43】动态规划Part11

1143.最长公共子序列 题目链接/文章讲解&#xff1a;代码随想录 视频讲解&#xff1a;动态规划子序列问题经典题目 | LeetCode&#xff1a;1143.最长公共子序列_哔哩哔哩_bilibili class Solution {public int longestCommonSubsequence(String text1, String text2) {// 将输…

使用three.js 实现蜡烛效果

使用three.js 实现蜡烛效果 import * as THREE from "three" import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"var scene new THREE.Scene(); var camera new THREE.PerspectiveCamera(60, window.innerWidth / window.in…

香港大学神作 LightRAG 横空出世!AI 检索生成系统革命,秒懂复杂信息,动态数据无所遁形!

❤️ 如果你也关注大模型与 AI 的发展现状&#xff0c;且对大模型应用开发非常感兴趣&#xff0c;我会快速跟你分享最新的感兴趣的 AI 应用和热点信息&#xff0c;也会不定期分享自己的想法和开源实例&#xff0c;欢迎关注我哦&#xff01; 微信订阅号&#xff5c;搜一搜&…

Python基础知识9

Python推导式 1.Python 推导式是一种独特的数据处理方式&#xff0c;可以从一个数据序列构建另一个新的数据序列的结构体。 2.Python 支持各种数据结构的推导式&#xff1a; 列表(list)推导式字典(dict)推导式集合(set)推导式元组(tuple)推导式 列表推导式 1.列表推导式格…

PHP DateTime基础用法

PHP DateTime 的用法详解 一、引言 在开发 PHP 应用程序时&#xff0c;处理日期和时间是一个至关重要的任务。PHP 提供了强大的日期和时间处理功能&#xff0c;其中 DateTime 类是最常用的工具之一。DateTime 类提供了丰富的方法来创建、格式化、计算和比较日期时间&#xff…

QT QML 练习8-Simple Transformations

简单的转换&#xff08;Simple Transformations&#xff09; 转换操作改变了一个对象的几何状态。QML元素对象通常能够被平移&#xff0c;旋转&#xff0c;缩放。下面我们将讲解这些简单的操作和一些更高级的用法。 我们先从一个简单的转换开始。用下面的场景作为我们学习的开始…