5

だから私にはやるべきプロジェクトがありますが、私は完全に困惑しています。私は10時間費やしましたが、どこにも行きませんでした。私は特にコードを答えにしたくありませんが、いくつかの疑似コードと正しい方向への良いヒントはヒープに役立ちます!!

k - パイプで接続されたコマンドライン引数 - 各プロセスは次のプロセスに接続され、最後のプロセスは最初のプロセスに接続されます。プロセス番号 k は、そのメッセージをプロセス番号 (k+1)%n に送信します。

プロセス 0 は から行を読み取りますstdin。次に、それをプロセス 1 に送信します。他の各プロセスは行を読み取り、文字列の最初のバイトを 1 ずつ増やしてから、その行を次のプロセスに中継します。中継すると、ステータス メッセージが表示されます (以下を参照)。

メッセージがプロセス 0 に戻ると、標準出力にも出力されます。EOFプロセスが (0 以外のプロセスの場合はパイプから、プロセス 0 の場合は から)を受信するstdinと、最終的な文字列を出力します。これにより、すべてのパイプが閉じられます。

予想される出力は次のとおりです。

$ ./ring 4
hello
process #0 (32768) sending message: hello
process #1 (32769) relaying message: iello
process #2 (32770) relaying message: jello
process #3 (32767) relaying message: kello
I hear kello
^C
$

私がこれまでに書いたこと:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define BUFFER_SIZE 80
#define READ_END 0
#define WRITE_END 1

int main(int argc, char *argv[])
{
    char readmsg[BUFFER_SIZE], readmsg2[BUFFER_SIZE], final[BUFFER_SIZE];
    int pid, process;
    int parent_child[2], child_parent[2];
    process = 0;

    if (pipe(child_parent) == -1) {
        fprintf(stderr, "Pipe failed");
        return 1;
    }
    if (pipe(parent_child) == -1) {
        fprintf(stderr, "Pipe failed");
        return 1;   
    }

    pid = fork();
    if (pid < 0) {
        fprintf(stderr, "Fork failed");
        return 1;
    } else if (pid > 0) {
        /* PARENT */
        read(0, &readmsg, BUFFER_SIZE);
        printf("process #%d (%d) sending message: %s", 
            0, getpid(), readmsg);
        write(parent_child[WRITE_END], &readmsg, BUFFER_SIZE);
        close(parent_child[WRITE_END]);
    } else {
        /* CHILD */
        read(parent_child[READ_END], &readmsg2, BUFFER_SIZE);
        readmsg2[0] += 1;
        printf("process #%d (%d) relaying message: %s", 
            1, getpid(), readmsg2);
        process += 1;
        write(child_parent[WRITE_END], &readmsg2, BUFFER_SIZE);
    }

    read(child_parent[READ_END], &final, BUFFER_SIZE);
    printf("I hear %d %s", pid - getpid(), final);

    return 0;
}

現在行っていることは、stdin から文字列を読み取り、それを最初のプロセスに渡し、プロセス 0 を出力します (ただし、実際には 0 を取得することはできません。単に 0 を出力するだけです)。次に、文字列をプロセス 1 にパイプし、バイト 1 を歪めます。次にパイプに再度書き込み、パイプの外側で文字列が読み取られ、歪んだ文字列が出力されます。

$ ./ring
hello
process #0 (6677) sending message: hello
process #1 (6678) relaying message: iello
I hear -6678 iello
^C
$ 

ここからどこへ行けばいいのかわからない。事前にありがとう、何でも役に立ちます!!

いくつかの助けを借りて、これは私が今持っているものです:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define BUFFER_SIZE 80
#define READ_END 0
#define WRITE_END 1

int main(int argc, char **argv) {
    char buf[BUFFER_SIZE];
    int process, rings, pid, pid_n, pid_n1, pid_1, i;
    int Pn[2];   //Pipe for process n   -> 0
    int Pn_1[2]; //Pipe for process n-1 -> n
    int Pn_2[2]; //Pipe for process n-2 -> n-1
    int P_0[2];  //Pipe for process 0   -> 1
    process = 0;

    if (argc == 2) {
        rings = atoi(argv[1]);
    } else {
        fprintf(stderr, "Usage: %s n, where n is number of rings\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    if ((pid = fork()) < 0) {
        fprintf(stderr, "Fork failed");
        return 1;
    } else if (pid == 0) {
        if ((pid_n = fork()) < 0) {
            fprintf(stderr, "Fork failed");
            return 1;
        } else if (pid_n == 0) {
            /* CHILD */
            close(Pn[WRITE_END]);
            close(Pn_1[READ_END]);
        } else {
            /* PARENT */
            close(Pn[READ_END]);
            close(Pn_1[WRITE_END]);
        }
        for (i = 0; i < rings; i++) {
            if ((pid_n1 = fork()) < 0) {
                fprintf(stderr, "Fork failed");
                return 1;
            } else if (pid_n1 == 0) {
                /* CHILD */
                close(Pn_1[WRITE_END]);
                close(Pn_2[READ_END]);
            } else {
                /* PARENT */
                close(Pn_1[READ_END]);
                close(Pn_2[WRITE_END]);
            }
        }

        /* Not sure about these last ones */
        if ((pid_1 = fork()) < 0) {
            fprintf(stderr, "Fork failed");
            return 1;
        } else if (pid_1 == 0) {
            /* CHILD */
            close(P_n2[WRITE_END]);
            close(P_0[READ_END]);

        } else {
            /* PARENT */
            close(P_n2[READ_END]);
            close(P_0[WRITE_END]);
        }
    } else {
        /* PARENT */
        read(0, &buf, BUFFER_SIZE);
        buf[BUFFER_SIZE - 1] = '\0';
        printf("process first # (%d) sending message: %s", getpid(), buf);
        write(P_0[WRITE_END], &buf, BUFFER_SIZE);
        read(Pn[READ_END], &buf, BUFFER_SIZE);
        buf[BUFFER_SIZE - 1] = '\0';
        printf("I hear %s", buf);
    }

    return 0;
}
4

2 に答える 2

8

これは、プロセスがどのように相互接続されるかを示すために私が自分で描いた図です。

                  p4
           C5 <--------- C4
          /               \
     p5  /              p3 \
        /                   \
o----> C0 ---->o            C3
        \                   /
     p0  \              p2 /
          \               /
           C1 ---------> C2
                  p1

Cnはプロセスを表します。C0 は親プロセスです。pnはパイプを表します。残りの 2 行は標準入力と標準出力です。子供たちにふさわしいように、各子供には簡単な仕事があります。親には、より複雑なタスクがあり、主に正確な数のファイル記述子が閉じられていることを確認します。実際、は非常に重要であるため、ファイル記述子が閉じられていることを条件付きで報告close()するデバッグ関数 を作成しました。fd_close()コードにばかげた間違いがあったときにもそれを使用しました。

err_*()関数は、ほとんどのプログラムで使用するコードの単純化されたバージョンです。複数の行を必要とするのではなく、ほとんどのエラー レポートを 1 行のステートメントに変換することで、エラー レポートの負担を軽減します。(これらの関数は通常 'stderr.c' と 'stderr.h' にありますが、これらのファイルは 750 行のコードとコメントであり、より包括的です。製品コードには、各メッセージの前に PID を付けることをサポートするオプションがあります。このようなマルチプロセス システムでも重要です。)

#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

enum { BUFFER_SIZE = 1024 };

typedef int Pipe[2];

static int debug = 0;
static void fd_close(int fd);

/* These functions normally declared in stderr.h */
static void err_setarg0(const char *argv0);
static void err_sysexit(char const *fmt, ...);
static void err_usage(char const *usestr);
static void err_remark(char const *fmt, ...);

static void be_childish(Pipe in, Pipe out)
{
    /* Close irrelevant ends of relevant pipes */
    fd_close(in[1]);
    fd_close(out[0]);
    char buffer[BUFFER_SIZE];
    ssize_t nbytes;
    while ((nbytes = read(in[0], buffer, sizeof(buffer))) > 0)
    {
        buffer[0]++;
        if (write(out[1], buffer, nbytes) != nbytes)
            err_sysexit("%d: failed to write to pipe", (int)getpid());
    }
    fd_close(in[0]);
    fd_close(out[1]);
    exit(0);
}

int main(int argc, char **argv)
{
    err_setarg0(argv[0]);

    int nkids;
    if (argc != 2 || (nkids = atoi(argv[1])) <= 1 || nkids >= 10)
        err_usage("n   # for n in 2..9");

    err_remark("Parent  has PID %d\n", (int)getpid());

    Pipe pipelist[nkids];
    if (pipe(pipelist[0]) != 0)
        err_sysexit("Failed to create pipe #%d", 0);
    if (debug)
        err_remark("p[0][0] = %d; p[0][1] = %d\n", pipelist[0][0], pipelist[0][1]);

    for (int i = 1; i < nkids; i++)
    {
        pid_t pid;
        if (pipe(pipelist[i]) != 0)
            err_sysexit("Failed to create pipe #%d", i);
        if (debug)
            err_remark("p[%d][0] = %d; p[%d][1] = %d\n", i, pipelist[i][0], i, pipelist[i][1]);
        if ((pid = fork()) < 0)
            err_sysexit("Failed to create child #%d", i);
        if (pid == 0)
        {
            /* Close irrelevant pipes */
            for (int j = 0; j < i-1; j++)
            {
                fd_close(pipelist[j][0]);
                fd_close(pipelist[j][1]);
            }
            be_childish(pipelist[i-1], pipelist[i]);
            /* NOTREACHED */
        }
        err_remark("Child %d has PID %d\n", i, (int)pid);
    }

    /* Close irrelevant pipes */
    for (int j = 1; j < nkids-1; j++)
    {
        fd_close(pipelist[j][0]);
        fd_close(pipelist[j][1]);
    }

    /* Close irrelevant ends of relevant pipes */
    fd_close(pipelist[0][0]);
    fd_close(pipelist[nkids-1][1]);

    int w_fd = pipelist[0][1];
    int r_fd = pipelist[nkids-1][0];

    /* Main loop */
    char buffer[BUFFER_SIZE];

    while (printf("Input:  ") > 0 && fgets(buffer, sizeof(buffer), stdin) != 0)
    {
        int len = strlen(buffer);
        if (write(w_fd, buffer, len) != len)
            err_sysexit("Failed to write to children");
        if (read(r_fd, buffer, len) != len)
            err_sysexit("Failed to read from children");
        printf("Output: %.*s", len, buffer);
    }
    fd_close(w_fd);
    fd_close(r_fd);
    putchar('\n');

    int status;
    int corpse;
    while ((corpse = wait(&status)) > 0)
        err_remark("%d exited with status 0x%.4X\n", corpse, status);

    return 0;
}

static void fd_close(int fd)
{
    if (debug)
        err_remark("%d: close(%d)\n", (int)getpid(), fd);
    if (close(fd) != 0)
        err_sysexit("%d: Failed to close %d\n", (int)getpid(), fd);
}

/* Normally in stderr.c */
static const char *arg0 = "<undefined>";

static void err_setarg0(const char *argv0)
{
    arg0 = argv0;
}

static void err_usage(char const *usestr)
{
    fprintf(stderr, "Usage: %s %s\n", arg0, usestr);
    exit(1);
}

static void err_vsyswarn(char const *fmt, va_list args)
{
    int errnum = errno;
    fprintf(stderr, "%s:%d: ", arg0, (int)getpid());
    vfprintf(stderr, fmt, args);
    if (errnum != 0)
        fprintf(stderr, " (%d: %s)", errnum, strerror(errnum));
    putc('\n', stderr);
}

static void err_sysexit(char const *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    err_vsyswarn(fmt, args);
    va_end(args);
    exit(1);
}

static void err_remark(char const *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
}

出力例:

$  ./pipecircle 9
Parent  has PID 34473
Child 1 has PID 34474
Child 2 has PID 34475
Child 3 has PID 34476
Child 4 has PID 34477
Child 5 has PID 34478
Child 6 has PID 34479
Child 7 has PID 34480
Child 8 has PID 34481
Input:  Hello
Output: Pello
Input:  Bye
Output: Jye
Input:  ^D
34474 exited with status 0x0000
34477 exited with status 0x0000
34479 exited with status 0x0000
34476 exited with status 0x0000
34475 exited with status 0x0000
34478 exited with status 0x0000
34480 exited with status 0x0000
34481 exited with status 0x0000
$
于 2013-11-07T15:11:15.017 に答える
1

これは2つのプロセスで機能するため、かなり近いようです。ここで行う必要があるのは、親からさらにプロセスを作成するためのループです。

(k=N+1 processes: proc0 = parent, proc1, ..., procN)
Create a pipe Pn, that will be for procN->proc0
Create a pipe Pn-1, that will be for procN-1->procN
Create relaying fork procN
    fork closes Pn output and Pn-1 input
    parent closes Pn input and Pn-1 output
(loop here)
Create a pipe Pi-2, that will be for procI-2->procI-1
Create relaying fork procI-1
    fork closes Pi-1 output and Pi-2 input
    parent closes Pi-1 input and Pi-2 output
...
Create a pipe P0 that will be for proc0->proc1
Create relaying fork proc1
    fork closes P1 output and P0 input
    parent closes P1 input and P0 output
(end loop)

(parent final code:)
Read from stdin
Write on P0
Read on Pn
Write on stdout

fork() で作成されると、子プロセス (つまり、proc0 を除く) はパイプの入力を閉じ (もう一方の出力は既に閉じられています!)、一方のメッセージを読み取り、他方に書き込み、終了します。

現在のコードに関するいくつかのコメント:

  • child_parent を読み取るとき、子はそのリスト ビットを実行するべきではありません。
  • それほど多くのバッファーは必要ありません (必要なのは 1 つだけ、フォーク後にプロセスごとに1 つになります)。
  • 印刷する前にいくつかの終端ヌルバイトを入れてください:)
  • 必要のない端を閉じることをお勧めします
于 2013-11-07T01:39:44.843 に答える