【问题标题】:How to make a process ring with fork and pipe?如何用叉子和管子制作工艺环?
【发布时间】:2016-11-26 19:30:40
【问题描述】:

目前我正在学习 C,我想用叉子和管道创建一个 n 进程,其中 n em> 是输入参数的数字,每个孩子可以与下一个孩子单向交流like this. 我尝试这样做,每个孩子将其 pid 发送给下一个孩子,但如果我创建 3 个孩子,我就得不到我想要的:

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

但我应该得到:

  1. PID:1,i 在循环中:0,收到:3
  2. PID:2, i in loop : 1, received : 1
  3. PID:3, i in loop : 2, received : 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);
}

【问题讨论】:

  • 你怎么知道代码错了?
  • 我用 printf 对其进行了测试,其中显示了 i、当前进程 id 和收到的整数,我应该得到每个孩子的前一个 pid,但我没有得到我应该得到的。跨度>
  • 在问题中添加您认为应该得到什么以及实际得到什么。

标签: c pipe fork child-process


【解决方案1】:

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

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

  2. 添加错误检查后,您将调查EBADF 错误的来源,并注意到管道未正确初始化。这是由于行pipe(&amp;t[2*i]); 应该使用k 而不是i。查找此错误的另一种方法是使用地址清理程序或 Valgrind,两者都会立即发现错误(根本无需更改代码)。循环内的范围循环变量也会立即发现此问题,因此请使用for (int i = 0; ...) 而不是int i; for (i = ; ...)

  3. close() 函数在循环结束后对已关闭的文件调用两次。然而,这个错误是无害的。

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

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

这是一个带有注释的更新版本:

#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".
}

【讨论】:

  • 谢谢,我明天去看看,如果有什么问题再回复你!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-27
  • 2011-12-17
  • 2018-05-26
  • 2017-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多