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

Unable to send message to parent process after multiple forks

本文关键字:进程 消息 分叉      更新时间:2023-10-16

我有一个程序,它分叉了四个进程并调用execlp()为孩子运行不同的代码。我给孩子一个数字作为 ID。到目前为止,子进程所做的只是尝试将 id 传递回父进程。如果我在父进程中打印出的流中放置一个字符串,管道就可以工作。但是,当我尝试将 id 作为 int 认为流时,它不起作用。我什至没有进入子命令中的 fprintf() 和 fflush() 命令之后的代码行。

我对创建文件描述符的方式进行了一些更改,并为示例添加了更多代码。现在,在孩子中,我无法创建 FILE*。但是,如果我在文件描述符 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 + '');
    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,但对其他孩子无效。有谁知道我的代码出了什么问题?

execlp(3)需要以空结尾的字符串,因为它是参数。 &cnt不会以 null 终止。

简单修复:

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

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

这是一个关于如何实现我评论中的建议的小例子:

#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: %sn", buffer);
        }
        fclose(fp);
        /* Wait for child to exit */
        wait(NULL);
    }
    return 0;
}

希望这足以让你继续前进。

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