如何用叉子和管子制作工艺环?
How to make a process ring with fork and pipe?
目前我正在学习 C,我想用 n childs 制作一个 环forks and pipes 其中 n 是参数中输入的数字,每个 child 可以与下一个 child 进行通信方向 like this.
我尝试在每个 child 发送到下一个 child 它的 pid 的地方做,但是我没有得到我想要的东西,例如,如果我创建 3 childs :
- PID:1,i 在循环中:0,接收到:0
- PID:2,我在循环中:1,接收到:0
- PID:3,我在循环中:2,接收到:0
但我应该得到:
- PID:1,i 在循环中:0,接收到:3
- PID:2,我在循环中:1,收到:1
- PID:3,我在循环中:2,收到:2
有时我会收到一个随机的值 child 到另一个这是我的代码,我不太适应循环中的多个管道。
#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()
将 return 为负结果。在这种情况下,您可能会从 read()
.
得到 EBADF
添加错误检查后,您将调查 EBADF
错误的来源,并注意到管道未正确初始化。这是由于行 pipe(&t[2*i]);
应该使用 k
而不是 i
。找到此错误的另一种方法是使用地址清理器或 Valgrind,它们都可以立即找到错误(根本无需更改代码)。循环内的范围循环变量也会立即发现这个问题,所以使用 for (int i = 0; ...)
而不是 int i; for (i = ; ...)
.
close()
函数在循环结束后对已经关闭的文件调用两次。然而,这个错误是无害的。
父进程应该等待它的子进程退出,它也应该先关闭管道。
该程序依赖行缓冲才能正常工作。一个好的解决方案是在调用 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".
}
目前我正在学习 C,我想用 n childs 制作一个 环forks and pipes 其中 n 是参数中输入的数字,每个 child 可以与下一个 child 进行通信方向 like this. 我尝试在每个 child 发送到下一个 child 它的 pid 的地方做,但是我没有得到我想要的东西,例如,如果我创建 3 childs :
- PID:1,i 在循环中:0,接收到:0
- PID:2,我在循环中:1,接收到:0
- PID:3,我在循环中:2,接收到:0
但我应该得到:
- PID:1,i 在循环中:0,接收到:3
- PID:2,我在循环中:1,收到:1
- PID:3,我在循环中:2,收到:2
有时我会收到一个随机的值 child 到另一个这是我的代码,我不太适应循环中的多个管道。
#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()
将 return 为负结果。在这种情况下,您可能会从read()
. 得到 添加错误检查后,您将调查
EBADF
错误的来源,并注意到管道未正确初始化。这是由于行pipe(&t[2*i]);
应该使用k
而不是i
。找到此错误的另一种方法是使用地址清理器或 Valgrind,它们都可以立即找到错误(根本无需更改代码)。循环内的范围循环变量也会立即发现这个问题,所以使用for (int i = 0; ...)
而不是int i; for (i = ; ...)
.close()
函数在循环结束后对已经关闭的文件调用两次。然而,这个错误是无害的。父进程应该等待它的子进程退出,它也应该先关闭管道。
该程序依赖行缓冲才能正常工作。一个好的解决方案是在调用
fork()
. 之前先
EBADF
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".
}