You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

未使用wait函数时父进程仍处于活跃状态的原因探究

问题:注释wait后父进程未退出,ps仍能同时看到父子进程

我使用管道展示文件内容,注释掉父进程末尾的wait(NULL)后,原本以为文件读取完成后父进程会退出,此时ps输出应该只剩子进程(less),但实际执行ps时能同时看到父进程(编译后的xpager)和子进程。运行平台为Ubuntu 22.04.4 LTS,编译代码生成可执行文件xpager后,通过xpager filename命令执行。

完整代码

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/wait.h>

#define BUFSIZE 8192
#define PPAGER  "/usr/bin/less"

int main(int argc, char *argv[]) {
    pid_t   pid;
    int eerrno, n;
    int in, pfd[2];
    char    buf[BUFSIZE];
    char    *pager, *argv0;


    if (argc != 2) {
        printf("usage: %s <pathname>\n", argv[0]);
        exit(1);
    }

    if ( (in = open(argv[1], O_RDONLY)) < 0) {
        eerrno = errno;
        printf("Open error. %s(%d)\n", strerror(errno), errno);
        exit(eerrno);
    }

    if ( pipe(pfd) < 0) {
        eerrno = errno;
        printf("pipe error. %s(%d)\n", strerror(errno), errno);
        exit(eerrno);
    }


    pid = fork();
    switch (pid) {
        case -1:
            eerrno = errno;
            printf("fork error. %s(%d)\n", strerror(errno), errno);
            exit(eerrno);

        case 0:
            close(pfd[1]);
            close(in);
            if (STDIN_FILENO != pfd[0]) {
                if (dup2(pfd[0], STDIN_FILENO) < 0) {
                    eerrno = errno;
                    printf("dup2 error. %s(%d)\n", strerror(errno), errno);
                    exit(eerrno);
                }
                close(pfd[0]);
            }
            if ((pager=getenv("PPAGER")) == NULL)
                pager = PPAGER;
            if ((argv0=strrchr(pager, '/')) != NULL)
                argv0++;
            else
                argv0=pager; 
            execlp(pager, argv0, argv[1], (char *)0);
        default:
            close(pfd[0]);
            while((n=read(in, buf, BUFSIZE)) > 0) {
                if (write(pfd[1], buf, n) < 0) {
                    eerrno = errno;
                    printf("write errno. %s(%d)\n", strerror(errno), errno);
                    kill (pid, 9);
                    exit(eerrno);
                }
            }
            if (n < 0) {
                eerrno = errno;
                printf("read error. %s(%d)\n", strerror(errno), errno);
                kill(pid, 9);
                exit(eerrno);
            }
            close(pfd[1]);
        //  wait(NULL);
    }

    exit(0);
}

精简版代码

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

#define BUFSIZE 8192
#define PPAGER  "/usr/bin/less"

int main(int argc, char *argv[]) {
        pid_t   pid;
        int     n,in, pfd[2];
        char    buf[BUFSIZE];
        char    *pager, *argv0;

        in = open(argv[1], O_RDONLY);
        pipe(pfd);

        pid = fork();
        switch (pid) {
                case 0:
                        close(pfd[1]);
                        dup2(pfd[0], STDIN_FILENO);
                        pager = PPAGER;
                        argv0="less";
                        execlp(pager, argv0, argv[1], (char *)0);
                default:
                        close(pfd[0]);
                        while ((n=read(in, buf, BUFSIZE)) > 0)
                                write(pfd[1], buf, n);
                        close(pfd[1]);
                //      wait(NULL);
        }
        return(0);
   }

问题原因分析

  • less未读取管道内容:代码中给less传递了文件名参数argv[1],less的默认行为是:如果传入文件名,就直接打开该文件读取,不会从标准输入(管道)读取数据。这导致管道的读端没有被消费。
  • 父进程被write阻塞:管道的缓冲区容量有限(默认约64KB),父进程不断向管道写入文件内容,但读端无读取操作,管道很快被写满,父进程的write调用会进入阻塞状态,无法执行后续的close和exit,因此父进程会一直存活。
  • less持续运行:less在展示文件时会保持运行状态,直到用户主动退出(如按q键),所以子进程会一直存在。

修复方案

如果希望父进程通过管道将内容传递给less,需去掉execlp中的文件名参数,让less从标准输入读取:

// 修正后的execlp调用
execlp(pager, argv0, (char *)0);

修改后,less会从管道读取父进程写入的内容,管道读端被持续消费,父进程写完文件后会正常关闭管道并退出(即使没有wait),此时ps只会显示运行中的less进程。

若保留wait(NULL),父进程会等待子进程退出后再终止,会一直存活到用户关闭less。

内容的提问来源于stack exchange,提问作者tahzibi.jafar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 13:19:50