用叉子的子进程

时间:2015-03-20 21:16:00

标签: c linux fork wait waitpid

我正在尝试创建一个简单的C程序,它将调用fork方法三次,并显示子进程的标识符(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);
}           

2 个答案:

答案 0 :(得分:4)

您的一个问题出在此代码中:

case 0:         
    identifiers();  
    break;

当然,你打算这样做:

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

否则子进程将继续执行,您将获得太多的分支。

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

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

答案 1 :(得分:3)

在这一行:

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

getpid()将始终获得父pid,而不是孩子的pid。 建议将switch(fork())更改为

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

waitpid

waitpid(pid, &status, 0);