简体   繁体   English

多次分叉后无法将消息发送到父进程

[英]Unable to send message to parent process after multiple forks

I have a program that forks off four processes and calls execlp() to run different code for the child. 我有一个程序,它分叉了四个进程并调用execlp()为子代运行不同的代码。 I pass the child a number as an id. 我给孩子传递了一个数字作为ID。 So far, all the child does is try to pass the id back to the parent process. 到目前为止,子级所做的只是尝试将id传递回父级进程。 The pipes work, if i put a string though the stream it prints out in the parent process. 管道工作,如果我在父进程中通过输出流放置了一个字符串。 However, when i try to put the id as an int thought the stream, it does not work. 但是,当我尝试将id作为一个int认为是流时,它不起作用。 I dont even get to the line of code after the fprintf() and fflush() command in the child. 在子级中的fprintf()和fflush()命令之后,我什至没有到达代码行。

I made some changes for how i created the file descriptors and added more code for an example. 我对创建文件描述符的方式进行了一些更改,并为示例添加了更多代码。 Now, in the child, i am unable to create the FILE* out. 现在,在孩子中,我无法创建FILE *。 However, if i create out on file descriptor 1, it does print to the screen. 但是,如果我在文件描述符1上创建出来,则它确实会打印到屏幕上。 I tried creating out on file descriptor 3 and the program just sits there and waits for input from the child that never comes. 我尝试在文件描述符3上创建出来,程序就坐在那儿,等待从未出现的孩子输入。

Here is my parent: 这是我的父母:

Mom::Mom():childCount(0)
{
    pipeCount = fileCount = 0;
    int fd[2];
    srand(time(NULL));

    for(int c=0; c<NUMJOBS; ++c) jobs[c] = newJob();
    //createFileDescriptors(fd);
    ret = pipe(fd);
    if(ret < 0) fatal("Error creating pipes");
    //cout << fd[0] << "\t"  << fd[1] << endl;
    pipes[fileCount++] = fdopen(fd[0], "r");
    fcntl( 3, F_SETFD, 0 );
    //close(fd[1]);
    //for(int c=3; c<FILEDESCRIPTORS; c+=2) pipes[pipeCount++] = fdopen(c, "w");
    createChildren();
    for(int c=0; c<4; c++)
    {
        int tmp = -1;
        //cout << "About to read from children, tmp = " << tmp << endl;
        ret = fscanf(pipes[0], "%d", &tmp);
        //char* buffer = (char*) malloc(80*sizeof(char));
        //char buffer[80];
        //read(3, buffer, 80);
        cout << ret << "\t" << tmp << endl;
        //cout << ret << " " << tmp << endl;
        //free(buffer);
    }
    //sleep(5);
}

/*------------------------------------------------------------------------------
  Create all the children by using fork() and execlp()
  ----------------------------------------------------------------------------*/
void Mom::createChildren()
{
    int fd[2];
    fcntl( fd[IN], F_SETFD, 0 );
    for(int c=0; c<NUMCHILDREN; c++)
    {
        ret = pipe(fd);
        if(ret < 0) fatal("Error creating pipes");
        int pid = fork();
        //cout << pid << endl;
        if(pid == 0)
        {
            setupChild(c, fd);
        }
        else
        {
            //close(fd[1]);

        }
    }
}

/*------------------------------------------------------------------------------
  set up the child and call exec to run ChildMain
  ----------------------------------------------------------------------------*/
void Mom::setupChild(int count, int fd[])
{
    //cout << "Creating child with id: " << count << endl;
    char cnt = '0' + count;
    string id_str (&cnt + '\0');
    fcntl( fd[0], F_SETFD, 0 );
    pipes[fileCount++] = fdopen(fd[1], "w");
    //execlp("ChildMain", "ChildMain",  id_str.c_str(), NULL);
    execlp("ChildMain",  id_str.c_str(), NULL);
}

And here is the child code: 这是子代码:

int main(int argc, char* argv[])
{
    //cout << argv[argc-1] << endl;
    if(argc < 1) fatal("Not enough arguments provided to ChildMain");
    int id = atoi(argv[argc-1]);
    //cout << *argv[1] << " " << id << endl;
    //redirect STDIN and STDOUT
    /*int c_in = dup(0);
    close(0);
    dup((2*id) + 5);
    int c_out = dup(1);
    close(1);
    dup(4);*/
    /////////////////////////////
    //Child kid((int) *argv[1]);
    FILE* out = fdopen(4, "w");
    if(out == NULL)
        cout << "Error opening stream to parent in child: " << id << endl;
    //char childID = '0' + id;
    //char buf[80];
    //strcpy(buf, "Child ");
    //strcat(buf, &childID);
    string buf ("Child");
    //cout << tmp << " " << childID << endl;
    //write(4, buf.c_str(), buf.length()+1);
    //cout << id << endl;
    int ret = fprintf(out, "%d", id);
    fflush(out);
    //fclose(out);
    //cout << id << " " << ret << endl;
    //ch.push_back((char) id);
    //put STDIN and STDOUT back to correct file descriptors
    /*close(1);
    dup(c_out);
    close(0);
    dup(c_in);*/
    ////////////////////////////////////////////////////////
    return 0;
}

I am very confused why this works for the first child, with id 0, but no the others. 我很困惑为什么这适用于ID为0的第一个孩子,而其他人没有。 Does anyone know what is wrong with my code? 有人知道我的代码有什么问题吗?

execlp(3) is expecting null terminated strings as it's args. execlp(3)期望以空终止的字符串作为参数。 &cnt won't be null terminated. &cnt不会以null终止。

Simple fix: 简单修复:

void Mom::setupChild(int count, int fd[])
{
    char cnt[2];
    cnt[0] = '0' + count;
    cnt[1] = '\0';
    fcntl( fd[(2*count)+3], F_SETFD, 0 );
    execlp("ChildMain", "ChildMain",  &cnt, NULL);
}

This doesn't scale to 10 processes though, so I'd probably use a buffer and just sprintf() into it. 不过,这不会扩展到10个进程,因此我可能会使用一个缓冲区,而只是将sprintf()放入其中。

Here is a small example on how to implement the suggestion in my comment: 这是一个有关如何在我的评论中实施建议的小例子:

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

int main()
{
    /* Need two sets of pipes: one for child stdin, one for child stdout */
    int pipefds1[2];
    int pipefds2[2];

    pipe(pipefds1);
    pipe(pipefds2);

    int rc = fork();
    if (rc == -1)
        perror("fork");
    else if (rc == 0)
    {
        /* In child */

        /* Close the old stdin and stdout */
        close(STDIN_FILENO);
        close(STDOUT_FILENO);

        /* Create new stdin/stroud from the pipes */
        dup2(pipefds1[0], STDIN_FILENO);
        dup2(pipefds2[1], STDOUT_FILENO);

        /* Close the unneeded pipe handles */
        close(pipefds1[1]);
        close(pipefds2[0]);

        /* Now pass control to the new program */
        execl("/bin/ls", "ls", "-l", "/", NULL);
    }
    else
    {
        /* In parent */

        /* Close the uneeded pipe handles */
        close(pipefds1[0]);
        close(pipefds2[1]);

        /* We want to use stdio functions */
        FILE *fp = fdopen(pipefds2[0], "r");

        /* Read all from the child */
        char buffer[128];
        while (fgets(buffer, sizeof(buffer), fp))
        {
            printf("Input from child: %s\n", buffer);
        }

        fclose(fp);

        /* Wait for child to exit */
        wait(NULL);
    }

    return 0;
}

Hopefully this will be enough for you to build on. 希望这足以让您继续。

The error handling is non-existant, but it is tested. 错误处理不存在,但是已经过测试。

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

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