【问题标题】:Child processes with fork带有 fork 的子进程
【发布时间】:2015-03-20 21:15:59
【问题描述】:

我正在尝试制作一个简单的 C 程序,它将调用 fork 方法 3 次并显示子进程的标识符(UID、GID、PID、PPID、PGID)。我正在努力正确理解真正发生的事情。在我的代码中,我对方法 fork() 和显示标识符使用单独的方法,对于父进程,我正在尝试使用 waitpid 方法等待所有子进程死亡。我现在真的很困惑,因为我无法让它以一种清楚地表明它以正确方式工作的方式工作。你能给我任何建议或为我的问题提供更好的方法吗?

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

void identifiers();
void forkMethod();

int main(void)
{ 
    forkMethod();
    return 0;
}

void forkMethod()
{
    int k;
    int status;
    for (k=0;k<3;k++){
        switch (fork()) {
        case -1:
            perror("fork error");
            exit(EXIT_FAILURE);
            break;
        case 0:         
            identifiers();  
            break;
        default:
            //wait(&status);
            waitpid(getpid(), &status, WNOHANG);
            sleep(1);
            break;
        }
    }
}

void identifiers()
{
    pid_t pid = getpid();
    pid_t ppid = getppid();
    pid_t pgid = getpgid(pid);
    pid_t uid = getuid();
    pid_t gid = getgid();
    printf("UID:%d GID:%d PID:%d PPID:%d PGID:%d\n", uid, gid, pid, ppid, pgid);
}

// ============================================== ===============

首先感谢大家的回答并指出我犯的所有这些错误,

我知道代码很糟糕,可能还有一些问题,但现在我想我已经有了我想要的。

@John Bollinger 询问我列出的主要功能是什么: 1. 编写一个函数,显示指定进程的标识符 UID、GUID、PID、PPID、PGID 2.调用fork()函数3次,显示子进程的这些标识符 3.使用休眠功能从最早的顺序显示进程 4. 根据结果显示进程树。

感谢@juhist 和@Jonathan Leffler 的简洁明了的解释。如果代码中有任何重大问题,请发布

知道最后的代码是:

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

void identifiers(); // function that display identifiers
void forkMethod(); // function that calls fork() function 3 times
void tree(int); // function displaying processes tree

int main(void)
{ 
identifiers(); // displaying ID's for parent process
printf("Parent pid: %d\n", getpid());   
printf("Child processes: \n");      

forkMethod();   

return 0;
}

void forkMethod()
{
int k;
int status;
int pid;

for (k=0;k<3;k++){
pid = fork();
    switch (pid) {
    case -1:
        perror("fork error");
        exit(EXIT_FAILURE);
        break;
    case 0: 
    identifiers(); 
    exit(0);             
    default:           
    tree(getpid());            
    wait(&status); 
        sleep(1);   
    break;
    }
}
}

void identifiers()
{
pid_t pid = getpid();
pid_t ppid = getppid();
pid_t pgid = getpgid(pid);
pid_t uid = getuid();
pid_t gid = getgid();
printf("\nUID:%d GID:%d PID:%d PPID:%d PGID:%d\n", uid, gid, pid, ppid, pgid);
}

void tree(int pid)
{
char pstree[] = "pstree -np "; 
char cmd[12];
sprintf(cmd, "%s%d", pstree, pid);
system(cmd);
}           

【问题讨论】:

  • 你到底在问什么?你的程序做了什么它不应该做的事情,或者它没有做什么它应该做的事情?
  • 在函数:identifiers() 中,应检查调用 'get...() 的每个返回值,以确保操作成功并处理任何错误事件
  • waitpid(getpid(),...) 让父母等待自己完成。如果您想等待特定的孩子,您需要 fork 返回的 pid
  • 作为术语说明,fork() 和其余部分是函数,而不是方法。 “方法”严格来说是面向对象编程系统中的一个术语。

标签: c linux fork wait waitpid


【解决方案1】:

您的问题之一在于这段代码:

case 0:         
    identifiers();  
    break;

您肯定是要这样做的:

case 0:
    identifiers();
    exit(0);

否则子进程会继续执行,你会得到太多的fork。

另一个问题是您使用父 pid 调用 waitpid(),而不是子 pid。当您使用 WNOHANG 参数时,这些调用没有任何用处。使用 wait() 或将 fork 返回的子进程的 pid 存储在某处,并将该 pid 用作 waitpid() 的参数。

此外,您应该考虑检查 waitpid() 的返回值。在较大的程序中,如果您有信号处理程序,则调用可能会被信号中断并返回带有 errno == EINTR 的错误代码。重试被信号中断的系统调用并检查其他可能的错误返回是一种很好的做法。

【讨论】:

  • 这是问题之一;它不是唯一的。
  • 我猜你的意思是 waitpid(getpid(), ...) 问题?是的,我也注意到了,但它似乎至少在我的 FreeBSD 系统上工作,所以我没有指出这一点。
  • 由于 WNOHANG 参数,它“有效”。该调用实际上没有任何用处,如果代码测试了来自 waitpid() 的返回值,就会知道这一点。
  • 您让我确信调用不正确(我之前认为父 pid 是“接受任何东西”的特例,因为它似乎有效),所以我编辑了答案。我现在建议也检查错误返回。
  • 好;谢谢。不过,我不能再投第二票了。
【解决方案2】:

在这一行:

waitpid(getpid(), &status, WNOHANG);

getpid() 将始终获取父 pid,而不是子 pid。 建议把switch(fork())改成

pid= fork(); switch(pid) { ... }

waitpid 行到

waitpid(pid, &status, 0);

【讨论】:

  • 这也是问题之一,但不是唯一的问题。注意另一个答案之后的讨论(当我输入时,只有两个答案)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-13
  • 2019-03-25
  • 1970-01-01
  • 1970-01-01
  • 2011-02-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多