当前位置: 首页 > article >正文

[操作系统] 进程等待

进程等待(Process Waiting)是操作系统中父进程用于管理和同步子进程的重要机制。根据你的图片内容,我们可以分几个部分来讲解进程等待的相关知识。


为什么需要进程等待?

当一个进程创建了子进程后,子进程会独立运行。如果父进程不进行等待,它可能会比子进程更早终止,导致子进程变成僵尸进程(Zombie Process),即进程已经终止但父进程没有回收它的资源,造成内存泄漏。

另外,进程⼀旦变成僵⼫状态,那就⼑枪不⼊,“杀⼈不眨眼”的kill -9 也⽆能为⼒,因为谁也没有办法杀死⼀个已经死去的进程。

我们需要知道⽗进程派给⼦进程的任务完成的如何。如,子进程是否完成,结果是否正确。

因此,父进程通过进程等待的⽅式,回收⼦进程资源,获取⼦进程退出信息


进程等待的方式

进程等待主要有两种方式:

  1. pid_t **wait**(int *status);** 函数**
  2. pid_t **waitpid**(pid_t pid, int *status, int options);** 函数**

wait 函数

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

pid_t wait(int *status);
  • wait 会阻塞父进程,直到任意一个子进程退出。
  • 返回退出的子进程的 PID。
  • status 指向一个整数变量,用于存储子进程的退出状态。

示例代码

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

这行代码会让父进程暂停执行,直到有一个子进程结束,并将其退出状态存储到 status 变量。


waitpid 函数

pid_t waitpid(pid_t pid, int *status, int options);
  • waitpid 提供比 wait 更灵活的进程等待方式。
  • pid 参数决定了要等待哪个子进程:
    • pid > 0:等待指定的子进程。
    • pid == -1:等待任意子进程(等价于 wait)。
    • pid == 0:等待与当前进程同组的任何子进程。
    • pid < -1:等待特定进程组的子进程。
  • options 参数:
    • 0:默认阻塞等待子进程退出。
    • WNOHANG:非阻塞模式,如果没有子进程退出,则立即返回 0
    • WUNTRACED:等待子进程停止(如 Ctrl+Z)。
    • WCONTINUED:等待已经继续执行的子进程(如 SIGCONT 信号)。

示例代码

int status;
pid_t pid = waitpid(-1, &status, 0);

此代码与 wait 类似,等待任意子进程结束。


如何获取子进程的退出状态?

waitwaitpid参数中的int *status是输出型参数,当做位图来看待,通过传入变量地址然后经过函数处理后得到对应结果,传入NULL则表示不关心子进程退出状态信息,否则操作系统会通过该参数将子进程的退出信息返回给父进程。

int有四字节,32比特位, waitpid 返回的 status 值只使用了 低 16 位(2 字节) 来存储进程的退出状态或终止信号信息。

具体的信息存储如图所示。

  1. 正常终止:如果进程是 **exit(n)** 退出的,
    • 高 8 位存储 exit(n) 返回的值 n
    • 低 7 位全 0,表示不是被信号终止的。
  2. 如果进程是被信号终止的
    • 低 7 位存储终止信号编号(如 SIGKILL=9)。
    • 第 7 位(bit 7)表示是否生成 core dump。(后续讲解)
    • 高 8 位无意义。

也就是说:

  • 正常退出:status = (exit_code << 8)
  • 信号终止:status = signal_number | (core_dump_flag << 7)

代码示例:

#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
    pid_t pid;
    if ( (pid=fork()) == -1 )
        perror("fork"),exit(1);
    
    if ( pid == 0 )
    {
        sleep(20);
        exit(10);
    } 
    else 
    {
        int st;
        int ret = wait(&st);
        if ( ret > 0 && ( st & 0X7F ) == 0 )
        { 
            // 正常退出
            printf("child exit code:%d\n", (st>>8)&0XFF);
        } 
        else if( ret > 0 ) { 
            // 异常退出
            printf("sig code : %d\n", st&0X7F );
        }
    }
}

测试结果:

# ./a.out #等20秒退出 
child exit code:10 
# ./a.out #在其他终端kill掉 
sig code : 9

信息的宏解析

子进程退出时,status 变量会存储一些信息,可以使用以下宏解析:

  • WIFEXITED(status):如果子进程正常退出,返回非零值。
    • WEXITSTATUS(status):获取子进程的退出码。
  • WIFSIGNALED(status):如果子进程是被信号终止的,返回非零值。
    • WTERMSIG(status):获取终止子进程的信号编号。
  • WIFSTOPPED(status):如果子进程因 SIGSTOP 进入暂停状态,返回非零值。
    • WSTOPSIG(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));
}

非阻塞等待

waitpid()参数中WNOHANG 选项可用于非阻塞模式,即如果没有子进程退出,则 waitpid 立即返回 0,不会阻塞父进程。

示例代码

while (1) 
{
    int status;
    pid_t pid = waitpid(-1, &status, WNOHANG);
    
    if (pid > 0) 
    {
        printf("Child %d exited\n", pid);
    } 
    else if (pid == 0) 
    {
        printf("No child exited yet\n");
    }
    sleep(1); // 避免 CPU 过载
}

进程等待的示意图

  1. 父进程调用 wait/waitpid 等待子进程结束
  2. 子进程执行任务后终止
  3. 父进程回收子进程资源,避免僵尸进程


进程等待的应用场景

  • 防止僵尸进程:确保子进程结束后,父进程回收其资源。
  • 管理多个子进程waitpid 可以指定等待特定的子进程,适用于多子进程管理。
  • 避免阻塞主进程:使用 WNOHANG 选项,使主进程可以继续执行其他任务。

总结

  • wait 适用于简单场景,等待任意子进程结束。
  • waitpid 提供更精细的控制,支持非阻塞模式。
  • WIFEXITED 等宏可以解析子进程的退出状态。
  • WNOHANG 选项可以实现非阻塞等待,防止父进程卡死。

http://www.kler.cn/a/542362.html

相关文章:

  • macbook2015升级最新MacOS 白苹果变黑苹果
  • Linux服务管理操作命令-systemctl命令
  • CSS3+动画
  • 【详细版】DETR系列之Deformable DETR(2021 ICLR)
  • 学习总结二十九
  • AMD 8845HS 780M核显部署本地deepseek大模型的性能
  • PHP设备巡检系统小程序
  • 掌握 PHP 单例模式:构建更高效的应用
  • C# Thread与Task的区别
  • 哪吒闹海!SCI算法+分解组合+四模型原创对比首发!SGMD-FATA-Transformer-LSTM多变量时序预测
  • python正则表示式学习笔记(一)
  • 【Elasticsearch】Bucket Count K-S Test 聚合
  • 详解状态模式
  • 每日学习 Spring Aop源码分析 具体是如何创建Aop代理的
  • 简要介绍C++的“类(Class)”
  • 快速部署 DeepSeek R1 模型
  • 网络工程师 (29)CSMA/CD协议
  • 如何在 Elasticsearch 中设置向量搜索 - 第二部分
  • 设计模式-结构型-外观模式
  • 【Elasticsearch】监控与管理:集群监控指标
  • http 与 https 的区别?
  • 使用MyBatisMyBatis Plus实现SQL日志打印与执行监控
  • 23种设计模式的定义和应用场景-02-结构型模式-C#代码
  • 青少年编程与数学 02-009 Django 5 Web 编程 05课题、数据库与ORM
  • PG高可用学习@2
  • 大模型基本原理(二)——ChatGPT的工作原理