waitpid()不等孩子

时间:2014-11-26 20:53:10

标签: c linux unix fork waitpid

我写了一个非常基本的shell,出于某种原因,当我使用fork()然后waitpid()时,父进程不会等待子进程。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <linux/limits.h>
#include "LineParser.h"
#include <termios.h>

#define MAX_STR 2048
void execute(cmdLine *pCmdLine);


int main()
{
    char isContinuing = 1;
    char path[PATH_MAX];
    char str[MAX_STR];
    char something[MAX_STR+PATH_MAX];
    cmdLine* cmd;
    while(isContinuing)
    {
        getcwd(path, PATH_MAX);
        printf("%s$ ", path);
        fgets(str, MAX_STR, stdin);
        if(!strncmp(str, "quit", strlen("quit")))
        {
            isContinuing = 0;
        }
        else
        {
            cmd = parseCmdLines(str);
            if(cmd->arguments != '\0')
            {
                execute(cmd);
            }
        }
    }

    freeCmdLines(cmd);
    return 0;
}

void execute(cmdLine *pCmdLine)
{
    pid_t id = fork();

    if(id == 0)
    {
        printf("I AM CHILD.\n");
        if(!execvp(pCmdLine->arguments[0], pCmdLine->arguments))
        {
            perror("execvp failed.\n");
            exit(1);
        }
        exit(0);
    }
    printf("I AM PARENT.\n");
    printf("WAITING FOR CHILD.\n");
    waitpid(id);
    printf("DONE WAITING\n");

}

LineParser头文件是我的,它完全正常工作。 现在,出于某种原因,只有第一个命令按预期工作, 我们假设输入“echo hi”,输出为:

I AM PARENT.
WAITING FOR CHILD.
I AM CHILD.
DONE WAITING.
按预期

然后打印“hi”和路径,再次等待命令。 出于某种原因,当我第二次输入SAME输入“echo hi”时,输出为:

I AM PARENT.
WAITING FOR CHILD.
DONE WAITING.
$PATH$ //(WITHOUT WAITING FOR INPUT !!!)
I AM CHILD.
hi
//and here waiting for input//

为什么会这样?

4 个答案:

答案 0 :(得分:1)

通过使用错误数量的参数调用waitpid()函数来调用未定义的行为。任何事情都可能发生。

这个简化的代码变体对我来说很好用:

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

int main ()
{
    int i;

    for (i = 0; i < 3; i += 1)
    {
        pid_t id = fork();

        if(id == 0)
        {
            char *argv[] = { "echo", "hi", NULL };

            printf("I AM CHILD.\n");
            execvp("echo", argv);
            /* failed to exec */
            perror("execvp failed.\n");
            exit(1);
        } else if (id < 0) {
            perror("fork failed.\n");
            exit(1);
        }
        printf("I AM PARENT.\n");
        printf("WAITING FOR CHILD.\n");
        waitpid(id, NULL, 0);
        printf("DONE WAITING\n");
    }

    return 0;
}

答案 1 :(得分:1)

您的代码存在一些问题:

  1. while循环
  2. 的每次迭代中都没有清除malloc&#39d内存
  3. 在无法访问的代码中添加exit()语句
  4. waitpid()功能
  5. 的参数列表不正确
  6. 执行功能中父代码与子代码之间的分离不清楚
  7. unused variable something
  8. 未能检查fgets函数
  9. 的返回值
  10. 缺少{/ 1} for sys / types.h
  11. 缺少{/ 1} for sys / wait.h
  12. IMO:问题应该包括#include
  13. 的定义

    所以这是一个可编译的代码版本。编译器发现原始代码存在许多问题。

    #include

答案 2 :(得分:0)

您对waitpid(2)的来电是错误的。

根据man 2 waitpid,它是:

pid_t waitpid(pid_t pid, int *status, int options);

您可能需要定义int并将其命名为:

waitpid(id, &status, 0);

或使用更简单的版本wait(2),它适用于任何孩子:

wait(&status);

答案 3 :(得分:0)

您的主要问题是您不要让编译器检查您的代码。您通常应该启用编译器警告并尝试理解它们。

$ gcc -Wall -Wextra -Werror -Os -c myshell.c

这是我使用的最小命令行。当您的代码使用这些设置进行编译时,您已经消除了代码中一堆难以发现的错误。正如其他人已经提到的那样,这些错误包括对waitpid的调用。

看看http://pubs.opengroup.org/onlinepubs/7908799/xsh/waitpid.html。在使用#include函数之前,Open Group规范要求您<sys/types.h>两个标头<sys/wait.h>waitpid。你的程序没有这样做。