#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<errno.h>
int main(int argc, char **argv){
int n = atoi(argv[1]);
int superdaddy = getpid();
int p[n+1][2];
int i=0;
int cpid,output;
int result = 0;
if(pipe(p[0])<0){
perror("1");
return 1;
}
if(pipe(p[n])<0){
perror("2");
return 1;
}
output = p[0][1];
if(getpid()==superdaddy){
if(write(p[0][1],&result,sizeof(result))<0){
perror("3");
return 1;
}
if(close(p[0][1])<0){
perror("4");
return 1;
}
}
while(1){
if(i==n){
if(read(p[n-1][0],&result,sizeof(result)<0)){
perror("5");
return 1;
}
result++;
output = p[n][1];
if(write(output,&result,sizeof(result))<0){
perror("6");
return 1;
}
if(close(p[n-1][0])<0){
perror("7");
return 1;
}
if(close(p[n][1])<0){
perror("8");
return 1;
}
break;
}
i++;
cpid = fork();
if(cpid==0){
if(i==n)
continue;
if(pipe(p[i])<0){
perror("9");
return 1;
}
if(read(p[i-1][0],&result,sizeof(result))<0){
perror("10");
return 1;
}
result++;
output = p[i][1];
if(write(output,&result,sizeof(result))<0){
perror("11");
return 1;
}
if(close(p[i-1][0])<0){
perror("12");
return 1;
}
if(close(p[i][1]<0)){
perror("13");
return 1;
}
continue;
}
else if(cpid<0){
perror("14");
return 1;
}
break;
}
if(getpid()==superdaddy){
wait(NULL);
if(read(p[n][0],&result,sizeof(result))<0){
perror("15");
return 1;
}
printf("Result: %dn",result);
if(close(p[n][0])<0){
perror("16");
return 1;
}
}
return 0;
}
程序的目的是从命令行读取一个数字n,然后派生n个子进程并创建n个管道。进程p0
是进程p1
的母体,进程p1
是进程p2
的母体,以此类推。一个变量(这里称为result)将通过管道传递,每次传递它都会加1。所以输出也应该是n。Fi
管道连接Pi
和P(i+1)
。附件是我的代码。
当n=1或n=2时,程序可以正确输出,分别为1和2。然而,当n=3时,它在错误5处给我一个糟糕的文件错误。我整个下午都在手工跟踪代码,但不知道它出了什么问题。有人能帮忙吗?先欣赏它吧!
当n=3时,它在错误5处给我一个坏文件错误。
这可以通过删除代码中的if(close(p[i][1]<0)){
来修复,因为您需要在上次迭代中读取p[i][0]
,即
if (i == n) {
if(read(p[n-1][0],&result,sizeof(result)<0)){
...
}
}
这是一个实现你的想法,我希望它可能会有所帮助:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s Nn", argv[0]);
exit(EXIT_FAILURE);
}
int n = atoi(argv[1]);
int pipes[n][2];
int i, val;
pid_t pid;
val = 0;
for (i = 0; i < n; i++) {
if (pipe(pipes[i]) < 0) {
perror("pipe");
exit(EXIT_FAILURE);
}
if ((pid = fork()) < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
else if (pid == 0) {
close(pipes[i][1]);
if (read(pipes[i][0], &val, sizeof(val)) != sizeof(val)) {
perror("read");
exit(EXIT_FAILURE);
}
printf("C %d read %dn", getpid(), val);
val++;
}
else {
close(pipes[i][0]);
printf("P %d writes %dn", getpid(), val);
if (write(pipes[i][1], &val, sizeof(val)) != sizeof(val)) {
perror("write");
exit(EXIT_FAILURE);
}
if (waitpid(pid, NULL, 0) != pid) {
perror("waitpid");
exit(EXIT_FAILURE);
}
printf("%d is going to leave.n", getpid());
exit(EXIT_SUCCESS);
}
}
printf("%d is going to leave.n", getpid());
exit(EXIT_SUCCESS);
}
测试运行:
$ ./a.out 3
P 2005 writes 0
C 2006 read 0
P 2006 writes 1
C 2007 read 1
P 2007 writes 2
C 2008 read 2
2008 is going to leave.
2007 is going to leave.
2006 is going to leave.
2005 is going to leave.
解释:
该代码的框架是for (i = 0; i < n; i++) { pipe(); fork(); }
,这意味着它将创建n
管道,n
新进程。在每次迭代中,父进程将写入pipes[i][1]
,子进程将读取pipes[i][0]
。最后,它将创建一个由一系列管道连接的流程链,并通过这一系列管道将值从第一个进程传递到最后一个进程。