繁体   English   中英

如何用叉子和管子制作工艺环?

[英]How to make a process ring with fork and pipe?

目前,我正在学习C,我想用叉子和管子使n个孩子的过程环化,其中n是一个数字作为参数输入,每个孩子都可以像这样在一个方向上与下一个孩子进行交流 我尝试在每个孩子向其下一个孩子发送其pid的位置上执行此操作,但是例如,如果我创建了3个孩子,我将得不到想要的东西:

  1. PID:1,i循环:0,接收:0
  2. PID:2,i在循环中:1,接收:0
  3. PID:3,我在循环中:2,收到:0

但是我应该得到:

  1. PID:1,i循环:0,接收:3
  2. PID:2,i循环:1,接收:1
  3. PID:3,i循环:2,接收:2

有时我从一个随机的孩子到另一个孩子收到一个值,这是我的代码,我对循环中的多个管道并不满意。

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

int main(int argc, const char * argv[]) {
    if(argc != 2) {
        fprintf(stderr, "Usage : %s <integer> [> 2]\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    int number_process = atoi(argv[1]);
    if(number_process < 2) {
        fprintf(stderr, "Usage : %s <integer> [> 2]\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    printf("Création de %d processus pour une élection : \n", number_process);
    int i = 0, j = 0, k = 0;
    int * t = (int *) malloc((2 * number_process) * sizeof(int));

    for(k = 0; k < number_process; k++) {
        pipe(&t[2*i]);
    }

    for(i = 0; i < number_process; i++) {
        if(fork() == 0) {
            for(j = 0; j < number_process*2; j++) {
                if(j != 2*i && j != ((2*i+3)%(number_process*2))) {
                    close(t[j]);
                }
            }
            close(t[(2*i+1)%(number_process*2)]);
            close(t[((2*i+2)%(number_process*2))]);

            int pid = (int) getpid();
            write(t[(2*i+3)%(number_process*2)], &pid, sizeof(int));

            int in = 0;
            read(t[i*2], &in, sizeof(int));
            printf("%d : %d\n", in, getpid()); 

            exit(EXIT_SUCCESS);
        }
    }
    return (EXIT_SUCCESS);
}

这是我在程序中发现的问题:

  1. 没有错误检查。 如果没有错误检查,则很难找到其他错误。 请注意,如果发生错误, read()将返回否定结果。 在这种情况下,您可能会从read()获得EBADF

  2. 添加错误检查后,您将调查EBADF错误的来源,并注意到管道未正确初始化。 这是由于pipe(&t[2*i]); 应该使用k而不是i 查找此错误的另一种方法是使用地址清理器或Valgrind,这两个方法都可以立即发现错误(而不必完全更改代码)。 在循环内部定义循环变量也将立即发现此问题,因此请使用for (int i = 0; ...)而不是int i; for (i = ; ...) int i; for (i = ; ...)

  3. 在已经关闭的文件循环结束后,两次调用close()函数。 但是,此错误是无害的。

  4. 父进程应等待其子进程退出,并且还应先关闭管道。

  5. 该程序依赖行缓冲才能正常工作。 一个好的解决方案是在调用fork()之前先进行fflush(stdout) fork()

这是带注释的更新版本:

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

void usage(const char *prog) {
    fprintf(stderr, "Usage : %s <integer> [> 2]\n", prog);
    exit(1);
}

int main(int argc, const char * argv[]) {
    if(argc != 2) {
        usage(argv[0]);
    }

    int number_process = atoi(argv[1]);
    if(number_process < 2) {
        usage(argv[0]);
    }

    printf("Création de %d processus pour une élection : \n", number_process);
    // Flush stdout before fork.
    fflush(stdout);

    // Do not cast the result of malloc
    // Use sizeof(*pipes) instead of sizeof(int)
    // Prefer descriptive variable names
    int *pipes = malloc((2 * number_process) * sizeof(*pipes));
    if (!pipes) {
        perror("malloc");
        exit(1);
    }

    // Scope loop variables in the loop
    for (int i = 0; i < number_process; i++) {
        int r = pipe(&pipes[2*i]);
        if (r == -1) {
            perror("pipe");
            exit(1);
        }
    }

    for (int i = 0; i < number_process; i++) {
        pid_t pid = fork();
        if (pid == -1) {
            perror("fork");
            exit(1);
        }
        if (pid == 0) {
            // Let's avoid copy/pasting 2*i and (2*i+3)%(number_process*2)
            // everywhere, which is hard to read
            int infd = pipes[2*i];
            int outfd = pipes[(2*i+3)%(number_process*2)];
            for (int j = 0; j < number_process*2; j++) {
                if (pipes[j] != infd && pipes[j] != outfd) {
                    close(pipes[j]);
                }
            }

            int self = getpid();
            ssize_t amt;
            amt = write(outfd, &self, sizeof(int));
            if (amt == -1) {
                perror("write");
                exit(1);
            }

            int in;
            ssize_t r = read(pipes[i*2], &in, sizeof(int));
            if (r == -1) {
                perror("read");
                exit(1);
            }
            printf("%d : %d\n", in, (int)getpid()); 

            exit(0);
        }
    }
    // Close pipes and wait for children to finish
    for (int i = 0; i < number_process * 2; i++) {
        close(pipes[i]);
    }
    for (int i = 0; i < number_process; i++) {
        wait(NULL);
    }

    // Return at end of main() is implicitly "return 0".
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM