[操作系统作业]os实验三:进程的管道通信
View Code
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <sys/types.h> 4 #include <unistd.h> 5 #include <string.h> 6 #include <sys/stat.h> 7 #include <fcntl.h> 8 #include <error.h> 9 #include <wait.h> 10 #define PSIZE 2 11 12 int main(){ 13 int fd[2]; 14 int flag = 1; 15 // 16 if((flag = pipe(fd)) == -1){ 17 printf("error in create pipe."); 18 exit(1); 19 }else if(flag == 0){ 20 // printf("success in create pipe."); 21 } 22 23 pid_t pid_1,pid_2; 24 char outpipe[50]; 25 // ******************问题所在********************// 26 if(((pid_1 = fork()) == -1)||((pid_2 = fork()) == -1)){ 27 // ******************问题所在********************// 28 printf("error in fork()!"); 29 } 30 else if(pid_1 == 0){ 31 printf("\n ...................%d %d...................\n",pid_1,pid_2); 32 printf("i am a child 1, my pid is %d ,my fatherpid is %d.\n",getpid(),getppid()); 33 lockf(fd[1],1,0);// 对管道的写入端口jia锁。 34 strcpy(outpipe,"Child process 1 is sending message!\n"); 35 printf("i am a child, i am writing %s \n",outpipe); 36 write(fd[1],outpipe,sizeof(outpipe)); 37 sleep(5); 38 lockf(fd[1],0,0);// 对管道的写入端口解锁。 39 //getchar();//must write 40 exit(0); 41 }else if(pid_2 == 0){ 42 printf("\n ...................%d %d...................\n",pid_1,pid_2); 43 44 printf("i am a child 2, my pid is %d ,my fatherpid is %d..\n",getpid(),getppid()); 45 lockf(fd[1],1,0);// 对管道的写入端口jia锁。 46 strcpy(outpipe,"Child process 2 is sending message!"); 47 printf("i am a child, i am writing %s \n",outpipe); 48 write(fd[1],outpipe,sizeof(outpipe)); 49 sleep(5); 50 lockf(fd[1],0,0);// 对管道的写入端口解锁。 51 //getchar();//must write 52 exit(0); 53 }else if(pid_1 > 0&&pid_2>0){ 54 printf("i am father, my pid is %d, my sonpid is %d and %d.\n",getpid(),pid_1,pid_2); 55 int i = 0; 56 pid_t pid; 57 while(i < PSIZE){ 58 if((pid = wait(0)) < 0){ 59 printf("error in waitepid.\n"); 60 exit(1); 61 }else{ 62 read(fd[0],outpipe,sizeof(outpipe)); 63 printf("father process read from pipe : %s son pid is %d.\n",outpipe,pid); 64 } 65 i++; 66 } 67 //getchar();//must write, if not ,the son process will be an orphen process. 相当于停了一下 68 exit(0); 69 } 70 }
错误在于父进程同时fork()生成两个子进程。
子进程有可能在连续fork过程中生成自己的子进程,是否生成与子进程执行的顺序相关。
简要说明:
执行顺序(应该是运行结果更恰当)
父进程:(pid :2000)
fork()(子进程pid :2001)||fork()(子进程pid :2002)
子进程2:(pid :2002)
fork()(子进程pid :2001)||fork()(子进程pid :0)
子进程1:(pid :2001)
fork()(子进程pid : 0 )||fork()(子进程pid :2003)
子进程至少保证了与所属父进程在调用fork()的位置处,fork()返回值为 0.
但是子进程继续fork(),返回值就与各进程的执行顺序相关了。
具体,比如 子进程2:pid 2001,我认为是由于父进程刚第一次fork,子进程2就fork了,那返回值为什么不是0呢?
这个问题我也不知到,欢迎大家指正。应该跟编译器有关。
最后结论:
父进程可以fork多个子进程,但是得一个一个fork,必须使得每fork一次后都需要有控制语句将其父子进程执行的程序段完全隔离开。避免使用 fork()||fork()连续fork子进程。
修改后:
View Code
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <sys/types.h> 4 #include <unistd.h> 5 #include <string.h> 6 #include <sys/stat.h> 7 #include <fcntl.h> 8 #include <error.h> 9 #include <wait.h> 10 #define PSIZE 2 11 12 int main(){ 13 int fd[2]; 14 int flag = 1; 15 if((flag = pipe(fd)) == -1){ //创建管道 16 printf("error in create pipe."); 17 exit(1); 18 }else if(flag == 0){ 19 // printf("success in create pipe."); 20 } 21 pid_t pid_1,pid_2; 22 char outpipe[50]; 23 if((pid_1 = fork()) == -1){ //创建子进程 24 printf("error in fork()!"); 25 }else if(pid_1 == 0){ //子进程执行代码段 26 printf("i am child 1, my pid is %d ,my fatherpid is %d.\n",getpid(),getppid()); 27 lockf(fd[1],1,0);// 对管道的写入端口jia锁。 28 strcpy(outpipe,"Child process 1 is sending message!\n"); 29 printf("i am writing : %s \n",outpipe); 30 write(fd[1],outpipe,sizeof(outpipe)); 31 sleep(5);// 让自己睡眠,好让父进程读出pipe内的数据。 32 lockf(fd[1],0,0);// 对管道的写入端口解锁。 33 //getchar();//must write 34 exit(0); 35 }else if(pid_1 > 0){ //父进程执行代码段 36 if((pid_2 = fork()) == -1){ 37 printf("error in fork()!"); 38 }else if(pid_2 == 0){ 39 printf("i am child 2, my pid is %d ,my fatherpid is %d..\n",getpid(),getppid()); 40 lockf(fd[1],1,0);// 对管道的写入端口jia锁。 41 strcpy(outpipe,"Child process 2 is sending message!"); 42 printf("i am writing : %s \n",outpipe); 43 write(fd[1],outpipe,sizeof(outpipe)); 44 sleep(5); 45 lockf(fd[1],0,0);// 对管道的写入端口解锁。 46 //getchar();//must write 47 exit(0); 48 } 49 printf("i am father, my pid is %d, my son pid is %d and %d.\n",getpid(),pid_1,pid_2); 50 int i = 0; 51 pid_t pid; 52 while(i < PSIZE){ 53 if((pid = wait(0)) < 0){//等待子进程结束后返回,返回值为子进程pid 54 printf("error in waitepid.\n"); 55 exit(1); 56 }else{ 57 read(fd[0],outpipe,sizeof(outpipe)); 58 printf("father process read from pipe : %s from son pid: %d.\n",outpipe,pid); 59 } 60 i++; 61 } 62 //getchar();//must write, if not ,the son process will be an orphen process. 相当于停了一下 63 exit(0); 64 } 65 }
关键在于子进程2,是如何执行父子共享代码段的。
修正:
wait函数,父进程需等待子进程结束后返回,才可继续执行。
因此,code中 子进程1,2的程序段中的sleep函数的作用:保证子进程将数据全部写入管道。
而非等待以保证父进程从管道中读出数据。