多个分叉后无法向父进程发送消息

时间:2012-06-20 00:46:34

标签: c++ c linux pipe

我有一个程序可以分离四个进程并调用execlp()来为子进程运行不同的代码。我把孩子作为身份传递给了一个号码。到目前为止,所有孩子都尝试将id传递回父进程。管道工作,如果我把一个字符串放在它在父进程中输出的流。但是,当我尝试将id作为int认为是流时,它不起作用。我甚至没有在孩子的fprintf()和fflush()命令之后找到代码行。

我对如何创建文件描述符进行了一些更改,并为示例添加了更多代码。现在,在孩子中,我无法创建文件*。但是,如果我在文件描述符1上创建,它会打印到屏幕上。我尝试在文件描述符3上创建,程序只是坐在那里等待来自未来的孩子的输入。

这是我的父母:

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

这是儿童代码:

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

我很困惑为什么这适用于第一个孩子,id为0,但没有其他孩子。有谁知道我的代码出了什么问题?

2 个答案:

答案 0 :(得分:0)

execlp(3)期待空终止字符串,因为它是args。 &cnt不会被空终止。

简单修复:

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

虽然这不会扩展到10个进程,所以我可能会使用缓冲区并只使用sprintf()。

答案 1 :(得分:0)

以下是关于如何在我的评论中实施建议的一个小例子:

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

希望这对你来说足够了。

错误处理不存在,但已经过测试。