[英]How to make a process ring with fork and pipe?
目前,我正在学习C,我想用叉子和管子使n个孩子的过程环化,其中n是一个数字作为参数输入,每个孩子都可以像这样在一个方向上与下一个孩子进行交流。 我尝试在每个孩子向其下一个孩子发送其pid的位置上执行此操作,但是例如,如果我创建了3个孩子,我将得不到想要的东西:
但是我应该得到:
有时我从一个随机的孩子到另一个孩子收到一个值,这是我的代码,我对循环中的多个管道并不满意。
#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);
}
这是我在程序中发现的问题:
没有错误检查。 如果没有错误检查,则很难找到其他错误。 请注意,如果发生错误, read()
将返回否定结果。 在这种情况下,您可能会从read()
获得EBADF
。
添加错误检查后,您将调查EBADF
错误的来源,并注意到管道未正确初始化。 这是由于pipe(&t[2*i]);
应该使用k
而不是i
。 查找此错误的另一种方法是使用地址清理器或Valgrind,这两个方法都可以立即发现错误(而不必完全更改代码)。 在循环内部定义循环变量也将立即发现此问题,因此请使用for (int i = 0; ...)
而不是int i; for (i = ; ...)
int i; for (i = ; ...)
在已经关闭的文件循环结束后,两次调用close()
函数。 但是,此错误是无害的。
父进程应等待其子进程退出,并且还应先关闭管道。
该程序依赖行缓冲才能正常工作。 一个好的解决方案是在调用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.