0

4 つのプロセスをフォークして 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 + '\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 の最初の子ではこれが機能するのに、他の子では機能しない理由が非常にわかりません。私のコードの何が問題なのか誰か知っていますか?

4

2 に答える 2

0

execlp(3) is expecting null terminated strings as it's args. &cnt won't be null terminated.

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.

于 2012-06-20T01:43:50.263 に答える
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;
}

うまくいけば、これはあなたが上に構築するのに十分であることを願っています.

エラー処理は存在しませんが、テストされています。

于 2012-06-21T12:37:49.557 に答える