0

まず第一に、はい、これは私のクラスの実験室の活動ですが、私はすでにこの演習を提出し、弁護しました。私が知りたいのは、このコードをより効率的に記述する別の方法があるかどうかです。

私たちの任務は、プロセスを作成するコードを作成することでした。プロセスは子を作成し、プロセスは別の子を作成し、最後に別の子を作成します。

*編集:読みやすくするために、要件を分離して番号を付けました:)

  1. 最後の子は、システムで実行中の現在のプロセスを示します。

  2. その親は単語を要求し、ユーザーの入力を使用してファイルを作成します。

  3. 次に、その親は単語またはフレーズを要求し、マシンのライブラリ内でそれを見つけます (たとえば、hi と入力すると、hi とそのディレクトリを含むファイルが検索され、一覧表示されるはずです。単語 hi の位置は重要ではありません)。 )

  4. 最後に、メインの親はその親 ID を出力するだけです。

そのための私の完全なコードは次のとおりです。

int main(void){ 
    char fileName[30];
    char phrase[30];
    int pid = fork();
    int fd[2];
    pipe(fd);
    if(pid==0){
        printf ("CHILD1: I am the 1st child\n");
        printf ("CHILD1: ID is %d \n", getpid());
        printf ("CHILD1: Parent ID is %d \n", getppid());
        int pid2 = fork();
        if(pid2==0){
            printf ("\t CHILD2: I am the 2nd child\n");
            printf ("\t CHILD2: ID is %d \n", getpid());
            printf ("\t CHILD2: Parent ID is %d \n", getppid());
            int pid3 = fork();      
                if(pid3==0){
                    printf ("\t\t CHILD3: I am the 3rd child\n");
                    printf ("\t\t CHILD3: ID is %d \n", getpid());
                    printf ("\t\t CHILD3: Parent ID is %d \n", getppid());
                    execlp ("/usr/bin/top", "top", NULL);
                }else if(pid3==-1){
                    printf ("ID is %d", getpid());
                    printf ("error");
                    exit(1);
                }else{
                    wait(NULL);
                    printf ("\t CHILD2: Enter a filename: ");
                    scanf ("%s", fileName);
                    printf ("\t CHILD2: %s was succcessfully created!\n", fileName);
                    execlp ("/bin/touch", "touch", fileName, NULL); 
                }
        }else if(pid2==-1){
            printf ("ID is %d", getpid());
            printf ("error");
            exit(1);
        }else{
            wait(NULL);
            int pid4 = fork();
                if(pid4 > 0) {
                    printf ("CHILD1: Enter a pharse: ");
                    scanf ("%s", phrase);
                    close(fd[1]);
                    close(STDIN_FILENO);
                    dup2(fd[0],STDIN_FILENO);
                    execlp ("/bin/grep", "grep", phrase, NULL);
                }else if (pid4 == 0) {
                    close(fd[0]);
                    close(STDOUT_FILENO);
                    dup2(fd[1],STDOUT_FILENO);
                    execlp ("/usr/bin/find", "find", NULL);
                }else {
                    printf ("error");
                }
        }       
    }else if(pid==-1){
        printf ("ID is %d", getpid());
        printf ("error");
        exit(1);
    }else{
        wait(NULL);
        printf ("PARENT: I am the parent\n");
        printf ("PARENT: ID is %d \n", getpid());
    }
}
4

1 に答える 1

0

あなたのコードは実行時間と行数の点ではかなり効率的ですが、深くネストされた単一のメイン関数は、あなたが行ったことを読んで理解しようとする人間にとってほとんど役に立ちません。

別のイディオムを考えてみましょう: よりモジュール化されたもので、プロセスの祖先が (IMHO) レビュー担当者がたどりやすいです。(また、top の代わりに ps を呼び出して、そのステップでキーボード操作を行う必要がないようにします。)

私のアプローチはより「効率的」ですか?間違いなくいいえ、私はこの関数ごとの子アプローチのより直接的なコーディングを好みますが。親プロセスと子プロセスの連鎖は人為的ですが、もちろんあなたの課題も人為的です。

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

/*
 * run the passed function in a child process, and return
 * from this function only if the child process runs and
 * exits with status of 0.
 */
static void
run_func_in_child(void (*f)())
{
    int status;
    pid_t pid = fork();

    switch (pid) {
    case -1:
        perror("fork");
        exit(1);
    case 0: /* child */
        (*f)();
        break;
    default: /* parent */
        if (waitpid(pid, &status, 0) == -1) {
             perror("waitpid");
             exit(1);
        }
        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
             return;
        }
        fprintf(stderr, "child did not exit cleanly\n");
        exit(1);
    }
}

/*
 * scanf would be simpler, but let's protect against buffer overruns
 */
static void
get_rsp(const char *prompt, char *buf, size_t blen)
{
    int bl;

    printf("%s: ", prompt);
    fflush(stdout);

    if (fgets(buf, blen, stdin) == NULL) {
        if (ferror(stdin)) {
            perror("read");
        }
        exit(1);
    }
    bl = strlen(buf);
    if (bl > 0 && buf[bl - 1] == '\n') {
        buf[bl - 1] = '\0';
    }
}

static void
child_4()
{
    execlp("/usr/bin/ps", "ps", "-www", "-e", "f", NULL);

    perror("exec /usr/bin/ps");
    exit(1);
}

static void
child_3()
{
    char buf[256];
    int fd;

    run_func_in_child(child_4);

    get_rsp("File name", buf, sizeof buf);

    if (access(buf, F_OK) == 0) {
        fprintf(stderr, "%s already exists\n", buf);
        exit(1);
    }

    if ((fd = creat(buf, 0644)) == -1) {
        perror("creat");
        exit(1);
    }
    close(fd);

    printf("Created empty file %s\n", buf);

    exit(0);
}

static void
child_2()
{
    char buf[80];
    int fd[2];
    pid_t pid;

    run_func_in_child(child_3);

    get_rsp("Phrase", buf, sizeof buf);

    if (pipe(fd) == -1) {
        perror("pipe");
        exit(1);
    }

    pid = fork();

    switch (pid) {
    case -1:
        perror("fork");
        exit(1);
    case 0:
        /* no explicit wait for this child-of-child
         * process, but when its parent (the grep) exits,
         * init becomes the parent, and does the wait
         */
        dup2(fd[1], 1);
        close(fd[0]);
        close(fd[1]);
        execlp("/usr/bin/find", "find", NULL);
        perror("exec of find");
        exit(1);
    default:
        dup2(fd[0], 0);
        close(fd[0]);
        close(fd[1]);
        execlp("/usr/bin/grep", "grep", buf, NULL);
        perror("exec of grep");
        exit(1);
    }
}

static void
child_1()
{
    run_func_in_child(child_2);

    printf("Child 1: pid is %d; ppid is %d\n", getpid(), getppid());

    exit(0);
}

int
main(int ac, char *av[])
{
    run_func_in_child(child_1);

    return 0;
}
于 2014-03-10T06:24:52.850 に答える