[英]Questions about Systm calls like fork() and pipe() in C
#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: %d\n",result);
if(close(p[n][0])<0){
perror("16");
return 1;
}
}
return 0;
}
该程序旨在从命令行读取数字n,然后分叉子进程并创建n个管道。 进程p0
将是进程p1
父进程, p1
将成为p2
父进程,依此类推。 一个变量(在这里命名为result)将通过管道传递,每次传递时它都将被添加1.因此输出也应该是n。 Pipe 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 N\n", 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 %d\n", getpid(), val);
val++;
}
else {
close(pipes[i][0]);
printf("P %d writes %d\n", 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(); }
for (i = 0; i < n; i++) { pipe(); fork(); }
for (i = 0; i < n; i++) { pipe(); fork(); }
,这意味着它将创建n
管道和n
新进程。 在每次迭代中,父级将写入pipes[i][1]
,子级将从pipes[i][0]
读取。 最终,它将创建一个由一系列管道连接的流程链,并通过该系列管道将值从第一个流程传递到最后一个流程。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.