简体   繁体   English

waitpid()不等待孩子

[英]waitpid() not waiting for child

I wrote a really basic shell and for some reason, when I use fork() and then waitpid() the parent process won't wait for the child. 我写了一个非常基本的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 header file is mine and it is fully working. LineParser头文件是我的,并且可以正常运行。 Now, for some reason, only the first command is working as expected, let's assume an input "echo hi", the output is: 现在,由于某种原因,只有第一个命令按预期运行,让我们假设输入“ echo hi”,输出为:

I AM PARENT.
WAITING FOR CHILD.
I AM CHILD.
DONE WAITING.

as expected and then it prints "hi" and the path, waiting for a command again. 如预期的那样,然后打印“ hi”和路径,再次等待命令。 For some reason, when I enter the SAME input "echo hi" the second time, the output is: 由于某种原因,当我第二次输入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//

Why does this happen? 为什么会这样?

You invoke undefined behavior by calling the waitpid() function with the wrong number of arguments. 您可以通过使用错误数量的参数调用waitpid()函数来调用未定义的行为。 Anything could happen. 什么事情都可能发生。

This simplified variant of your code works fine for me: 您的代码的这种简化变体对我来说很好用:

#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;
}

There are several problems with your code: 您的代码有几个问题:

  1. not clearing malloc'd memory on every iteration through the while loop 不通过while循环在每次迭代中清除malloc的内存
  2. putting a exit() statement in unreachable code exit()语句放入无法访问的代码中
  3. incorrect parameter list for the waitpid() function waitpid()函数的参数列表不正确
  4. unclear delination between parent code and child code in execute function 执行函数中父代码和子代码之间的不清楚的定义
  5. unused variable something 未使用的变量something
  6. failed to check return value from fgets function 无法检查fgets函数的返回值
  7. missing #include for sys/types.h 缺少sys / types.h的#include
  8. missing #include for sys/wait.h 缺少sys / wait.h的#include
  9. IMO: the question should have included the definition of struct cmdLine IMO:问题应该包括struct cmdLine的定义

So here is a compilable version of your code. 因此,这是您的代码的可编译版本。 The compiler found many problems with the original code. 编译器发现原始代码有很多问题。

#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>
#include <sys/types.h>
#include <sys/wait.h> // prototype for waitpid()


//note: pid_t waitpid(pid_t pid, int *status, int options);


struct cmdLine
{
    char ** arguments; // arguments[x] = ptr to an argument string
};

#define MAX_STR  (2048)
#define MAX_PATH (256)
void execute(struct cmdLine *);
struct cmdLine * parseCmdLines( char * );
void freeCmdLines( struct cmdLine * );



int main()
{
    char path[PATH_MAX];
    char str[MAX_STR];
    //char something[MAX_STR+PATH_MAX];
    struct cmdLine* pCmd = NULL;

    while(1)
    {
        getcwd(path, PATH_MAX);
        printf("%s$ ", path);
        if( NULL == fgets(str, MAX_STR, stdin) )
        {
            perror( "fgets failed" );
            exit( EXIT_FAILURE );
        }

        // implied else

        if(!strncmp(str, "quit", strlen("quit")))
        { // then strings equal
            break;  // exit while loop (and pgm)
        }

        // implied else input not equal 'quit'

        pCmd = parseCmdLines(str);
        if( (NULL != pCmd) && (NULL != pCmd->arguments) )
        { // then one or more arguments entered/parsed
            execute(pCmd);
        } // end if

        freeCmdLines(pCmd);  // free all strings memory, then free struct memory
        pCmd = NULL; // cleanup
    } // end while

    return 0;
} // end function: main


void execute(struct cmdLine *pCmdLine)
{
    int status = 0;
    pid_t id = fork();

    if(id == 0)
    { // then, child
        printf("I AM CHILD.\n");
        if(!execvp(pCmdLine->arguments[0], pCmdLine->arguments))
        { // if no error then never gets here
            perror("execvp failed.\n");
        } // end if
    }

    else
    { // else, parent
        printf("I AM PARENT.\n");
        printf("WAITING FOR CHILD.\n");
        waitpid(id, &status, 0);
        printf("DONE WAITING\n");
    } // end if
} // end function: execute

Your call to waitpid(2) is wrong. 您对waitpid(2)调用是错误的。

According to man 2 waitpid , it's: 根据man 2 waitpid ,它是:

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

You probably need to define an int and call it as: 您可能需要定义一个int并将其称为:

waitpid(id, &status, 0);

or use the simpler version wait(2) , which will work for any child: 或使用更简单的版本wait(2) ,该版本适用于任何孩子:

wait(&status);

Your main problem is that you don't let the compiler check your code. 您的主要问题是您不让编译器检查您的代码。 You should generally enable the compiler warnings and try to understand them. 通常,您应该启用编译器警告并尝试理解它们。

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

This is the minimum command line I use. 这是我使用的最小命令行。 When your code compiles with these settings, you have already eliminated a bunch of hard-to-find bugs in your code. 使用这些设置编译代码时,您已经消除了代码中许多难以发现的错误。 Among these bugs is, as others already have mentioned, the call to waitpid . 正如其他人已经提到的那样,这些bug中包括对waitpid的调用。

Have a look at http://pubs.opengroup.org/onlinepubs/7908799/xsh/waitpid.html . 看看http://pubs.opengroup.org/onlinepubs/7908799/xsh/waitpid.html The Open Group specification requires that you #include the two headers <sys/types.h> and <sys/wait.h> before using the waitpid function. Open Group规范要求在使用waitpid函数之前, #include两个头文件<sys/types.h><sys/wait.h> Your program doesn't do this. 您的程序不执行此操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM