Linux操作系统pipe通信与互斥探究

来源:互联网 发布:中国进出口最新数据 编辑:程序博客网 时间:2024/04/30 15:57

三、实验内容

编写一段程序,使用管道来实现父子进程之间的进程通信。子进程项父进程发送自己的进程表示符,以及某字符串。父进程则通过管道读出子进程发来的消息,将消息显示在屏幕上,然后终止。

四、程序设计-源程序

#include<stdio.h>#include<unistd.h>#include<stdlib.h>int main(){int fpid;//用于记录fork()返回值int fd[2];//用于记录pipe文件的读写端int ret_pipe;//用于接收pipe()的返回值ret_pipe=pipe(fd);if(ret_pipe==-1){//创建管道失败exit(1);}//创建管道成功之后执行以下代码:fpid=fork();if(fpid<0)//创建子进程失败{exit(1);}else if(fpid==0)//子进程执行代码{lockf(fd[1],1,0);//锁上写端char w_buffer[1024];int len=sprintf(w_buffer,"Write by Child Process,my id:%d\n",getpid());write(fd[1],w_buffer,len*sizeof(char));lockf(fd[1],0,0);//解锁写端exit(0);}else//父进程执行代码{sleep(3);//确保子进程先写再读lockf(fd[0],1,0);//锁上读端char r_buffer[1024];read(fd[0],r_buffer,sizeof(r_buffer));lockf(fd[0],0,0);//解锁读端waitpid(fpid,NULL,0);//等待子进程完结printf("Parent Process read form pipe:%s",r_buffer);exit(0);}}

五、程序调试

一开始编写程序的时候用的是close(fd[1]);或者是close(fd[0]);作用是关闭了读写端,lockf()函数与之比较起来更加灵活,lockf函数并不是关闭读写端而是锁起来,达到了互斥的效果,但是这个程序中子进程写,父进程读,并且sleep函数也提供足够时间让子进程把内容先写进去,不怎么可以体现到那种互斥的效果,除此之外read函数在写端存在的时候,pipe文件无内容读时也会自我阻塞,我会在后面的实验分析那里详细写处本人的一些探究过程与的出的结论。

六、实验结果

实验结果可以看得出父子进程之间的的确确进行了通信,子进程把“Write by Child Process,id:..."这个字符串写进了pipe文件,而父进程从pipe文件中读取了这个字符串,并且结合了一个"Parent Process read from pipe"的字符串输出,截图结果正好可以体现出通信。

七、实验分析

这次实验感觉互斥的体现不是很好,我的一些同学做了个试验说lockf(fd[1],1,0);这个锁写端的语句根本起不到锁的作用,其他进程照写无误,网上有关pipe互斥的探究貌似很少,探究过程挺困难的。

下面是一个这样的例子:2个进程

子进程:

else if(fpid==0){if(0==lockf(fd[1],1,0)){printf("write lock success\n");}for(i=0;i<10;i++){int len=write(fd[1],msg1,sizeof(msg1));printf("%d write by child\n",len);sleep(1);}exit(0);}
子进程向pipe文件写10次msg1,每写一次就打印一次write by child,看前面的len的值就能知道write函数成功与否

父进程:

else if(fpid>0){sleep(3);for(i=0;i<10;i++){int len=write(fd[1],msg2,sizeof(msg2));printf("%d write by Parent\n",len);sleep(1);}exit(0);}
父进程先sleep三秒好让子进程先运行,接着父进程也向pipe文件写msg2,并且每写一次都打印一次write by parent


理应是先运行的子进程锁起了写端,父进程没法写才对,但是结果却是:

从结果可以看到child在write的过程中有parent的write,那么child的lockf()的确是没起到作用哦。

我之后从网上找到个代码,修改了一下,终于体现到了互斥的效果了。

先来讲了那个代码做的是什么吧:首先3个进程,一个父进程一直从pipe文件读数据,另外2个子进程分别往pipe文件写10次不同的数据。

父进程:

while (read(fd[0],szRecv,50) > 0) {                puts(szRecv);            }exit(0);
子进程1:

        sleep(5);        if (lockf(fd[1],F_LOCK,0)) {            write(fd[1], "failed to lock", 50);            exit(0);        }        for (index=0; index<10; index++) {                write(fd[1],szMsg1,50);                sleep(1);        }//while(1);        lockf(fd[1],F_ULOCK,0);        exit(0);
子进程2:

 if (lockf(fd[1],F_LOCK,0)) {                write(fd[1], "failed to lock", 50);                exit(0);           }            write(fd[1],szMsg2,50);    for (index=0; index<10; index++) {                write(fd[1],szMsg2,50);                sleep(1);}    if(lockf(fd[1],F_ULOCK,0)){write(fd[1], "failed to unlock", 50);                exit(0);}            exit(0);
子进程1先sleep五秒,让子进程2先写数据。

实验结果:

子进程2写的时候,连续输出的p2.....中子进程1是没办法插入p1......的,只有当子进程2解锁了写端,子进程1才能写,所以截图可以看到p1.....全部都在p2......的后面,互斥就体现出来了。

另外在此程序的基础上我也做了很多不同的尝试:把2个子进程锁写端的代码注释起来:

注释掉锁写端的代码就会出现p1.....与p2......交替无序出现,明摆没能互斥,所以首先得出的结论是:lockf()的确有锁的效果的。

再来把子进程1的解锁代码注释掉,也注释掉sleep语句,让子进程先运行吧:

子进程1锁住了写端,所以子进程2无法写p2.....不会插在p1.......之间这很正常,但是我注释掉了解锁的代码,为何子进程2还能写东西,输出p2.......呢,这是由于子进程1写完之后结束进程,自动解锁了,为了证明这点,我在子进程那里加了while(1);这个死循环,不让子进程1结束,就不会解锁了:

可以看到这次p2.....就没再出现了,因为我没解锁写端,子进程2没办法写东西进pipe文件,这里得出的第二个结论:进程结束的时候会自动解锁。

到这里,这个示范程序几乎可以想到的部分都可以解释到了,可以完全体现到使用lockf函数达到的互斥效果。

但是一开始我们编写的2个进程的那个代码为什么却不像这里p1......与p2.......分开输出,而是child.....与parent....交替出现呢。我花了很长时间去对比这2个源代码,终于发现了突破点:lockf(fd[1],1,0);这个语句有检测的作用啊,在子进程里锁了写端,如果在父进程没lockf(fd[1],1,0);这句锁写端的代码它同样能够写进去pipe的,补上这句之后,一切就正常了:

这次运行结果就能完全体现到互斥效果了,子进程锁了写端,在写的过程中,父进程是无法写的,除非子进程解锁了或者是子进程结束了。


到此为止,pipe通信的互斥探究已经可以利用lockf函数来达到互斥效果了。



0 0