视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
操作系统实验三进程的管道通信
2025-09-30 19:42:01 责编:小OO
文档
实验三 进程的管道通信

一、实验目的:

(1)加深对进程概念的理解,明确进程和程序的区别;

(2)学习进程创建的过程,进一步认识并发执行的实质;

(3)分析进程争用资源的现象,学习解决进程互斥的方法;

(4)学习解决进程同步的方法;

(5)掌握Linux系统进程间通过管道通信的具体实现方法。 

二、实验内容及要求:

(1)使用系统调用pipe()建立一条管道线,两个子进程分别向管道写一句话(写的内容自己定,但要有该进程的一些信息);

(2)父进程从管道中读出来自两个子进程的消息,显示在屏幕上;

(3)要求:父进程首先接收子进程p1发来的消息,然后再接收子进程p2发来的消息;

(4)两个子进程要并发执行;

(5)实现管道的互斥使用。当一个子进程正在对管道进行写操作时,另一个欲写入管道的子进程必须等待。 使用系统调用lockf(fd[1],1,0)实现对管道的加锁操作,用lockf(fd[1],0,0)解除对管道的锁定;

(6)实现父子进程的同步,当父进程试图从一空管道中读取数据时,便进入等待状态,直到子进程将数据写入管道返回后,才将其唤醒。

三、实现:

相关的系统调用

fork()  用于创一个子进程。

   格式:int fork();

   返回值:在子进程中返回0;在父进程中返回所创建的子进程的ID值;当返回-1时,创建失败。

wait()  常用来控制父进程与子进程的同步。

    在父进程中调用wait(),则父进程被阻塞,进入等待队列,等待子进程结束。当子进程结束时,父进程从wait()返回继续执行原来的程序。

    返回值:大于0时,为子进程的ID值;等于-1时,调用失败。

exit() 是进程结束时最常调用的。

    格式:void exit( int status); 其中,status为进程结束状态。 

pipe()  用于创建一个管道 

    格式:pipe(int fd);

    其中fd是一个由两个数组元素fd[0]和fd[1]组成的整型

    数组,fd[0]是管道的读端口,用于从管道读出数据,fd[1]是管道的写端口,用于向管道写入数据。

    返回值:0 调用成功;-1 调用失败。

sleep() 使调用进程睡眠若干时间,之后唤醒。

     格式:sleep(int t);   其中t为睡眠时间。

lockf() 用于对互斥资源加锁和解锁。在本实验中该调用的格式为:

     lockf(fd[1],1,0);/* 表示对管道的写入端口加锁。

     lockf(fd[1],0,0);/* 表示对管道的写入端口解锁。

write(fd[1],String,Length) 将字符串String的内容写入  管道的写入口。 

read(fd[0],String,Length) 从管道的读入口读出信息放入字符串String中。

程序流程图

图1 父进程流程图

图2 子进程P1流程图

四、运行结果及说明

五、源代码

#include

#include

#include

#include

#include

#include

#include

#include

int main( ){

    int pid1,pid2,pid3;

    int fd[2];

    char outpipe[60],inpipe[60];

    pipe(fd);//创建一个管道

    while ((pid1=fork( ))==-1);

    printf("pid1=%d\\n",pid1);

    if(pid1==0){

         printf("The Child process 1 is sending message!\\n");

        lockf(fd[1],1,0);//互斥

        sprintf(outpipe,"This is the child 1 process's message!\\n");

        write(fd[1],outpipe,60);

        sleep(1);//自我阻塞1秒,让出机会执行下一个进程,增加并发度

        lockf(fd[1],0,0);

        exit(0);

    }

    else{

        while((pid2=fork( ))==-1);

        printf("pid2=%d\\n",pid2);

        if(pid2==0){

             printf("The Child process 2 is sending message!\\n");

            lockf(fd[1],1,0);

            sprintf(outpipe,"This is the child 2 process's message!\\n");

            write(fd[1],outpipe,60);

            sleep(1);

            lockf(fd[1],0,0);

            exit(0);

        }

        else{

            while((pid3=fork( ))==-1);

            printf("pid3=%d\\n",pid3);

            if(pid3==0){

                printf("The Child process 3 is sending message!\\n");

                lockf(fd[1],1,0);

                sprintf(outpipe,"This is the child 3 process's message!\\n");

                write(fd[1],outpipe,60);

                sleep(1);

                lockf(fd[1],0,0);

                exit(0);

            }

            else{

                wait(0);//同步

                read(fd[0],inpipe,60);

                printf("\\n%s",inpipe);

                wait(0);

                read(fd[0],inpipe,60);

                printf("%s\\n",inpipe);

                wait(0);

                read(fd[0],inpipe,60);

                printf("%s\\n",inpipe);

                exit(0);

            }

        }

    }

    return 0;

}

六、回答问题

(1)指出父进程与两个子进程并发执行的顺序,并说明原因。

子进程先执行,然后父进程才执行。

这是由进程的同步机制决定的,因为只有子进程向管道中写入信息后,父进程才能读取;否则父进程自己调用wait()系统调用将自己阻塞,将处理机交由子进程。

(2)若不对管道加以互斥控制,会有什么后果?

管道进行互斥控制,是为防止两个子进程对管道资源进行争夺而产生信息丢失或覆盖。如果不加控制,那么可能一个子进程写入的信息还没来得及被父进程读出,另一个子进程又先写入信息,那么之前的进程写入的信息将被覆盖,父进程也就读不到之前进程传递来的信息了。

(3)说明你是如何实现父子进程之间的同步的。

1、父进程读出之前确定管道中有数据,否则阻塞自己。

这一点很容一般到,通过系统调用wait()函数,即可以实现,当子进程结束时父进程才执行,那么此时管道中肯定已经有子进程写入的数据了。

2、子进程在写入之前要确定管道中的数据已经被父进程读出,否则不能写入或者阻塞自己。

3、这可以通过进程间的互斥来间接的办到。因为子进程间的互斥,所以每个子进程在执行开始都对管道pipe加锁,那么这样同时就只能有一个子进程向管道写入数据,并且子进程在向管道中写入数据后还要调用sleep()系统调用睡眠若干时间,那么这样就可以保证父进程能够从管道中读出数据。然后下一子进程才能写入。那么这样就保证了开头所说的子进程在写入之前要确定管道中的数据已经被父进程读出,否则不能写入或者阻塞自己。下载本文

显示全文
专题