进程的管道通信

记录于2022.7.7——南林操作系统课程设计心得

ps:这个实验也是让我写了很长时间


<任务>

     编写一段程序,实现进程的管道通信。使用系统调用pipe()建立一条管道线。两个子进程p1和p2分别向管道写信息,而父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <iostream>

int main() {
    // 用于存储文件描述符(相当于指针,记录的是下标)
    int fd[2];    
    // 定义两个进程变量
    pid_t pid1, pid2;
    // 写空间(用于暂存写入管道的数据)
    char buffer[128];       

    // 父进程调用pipe()函数创建管道,得到两个文件描述符fd[0]、fd[1]
    pipe(fd);
    
    // fd[0]指向管道的读端,fd[1]指向管道的写端
    // 父进程调用fork()函数创建子进程,那么子进程也有两个文件描述符指向同一管道
    // 父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道中写入数据,子进程将管道中的数据读出
    // 由于管道是利用环形队列实现的,数据从写端流入管道,从读端流出,这样就实现了进程间通信

    // 创建子进程1
    while ((pid1 = fork()) == -1);          

    // 如果此时是子进程1在运行
    if (pid1 == 0) {   
        std::cout << "Child process 1 is working!" << std::endl;
        /*
            int lockf(int files,int function,long size)
            files是文件描述符;
            function是锁定和 解锁;1 表示锁定,0 表示解锁;
            size是锁定和解锁的字节数,若用 0,表示从文件的当前 位置到文件尾

            LOCKF主要是给文件上锁。
            当p2进程想要访问文件是或者给文件上锁,那么就要等待p1释放锁,
            此时p2处于睡眠状态但当p1解开锁时,p2就可以向管道中写入数据。
            其目的在于控制p1、p2同时向管道中写入数据。
        */

        // 进程1给管道的写端上锁
        lockf(fd[1], 1, 0);   
        /*
            写操作:write(fd[1],buf,size)    
            buf:写空间,size :要写入的字符长度
            会从buf所指的内存中读出size个字符放到fd所指的文件中

            读操作:read(fd[0],buf,size)     
            buf:读空间,size :要读出的字符长度
            会从fd所指的文件中读出size个字符放入buf指针所指的内存中
        */
        // 进程1往写空间中写入字符串
        sprintf(buffer, "Child process 1 is sending a message!");       
        // 进程1从写空间中读出40个字符存入管道中
        write(fd[1], buffer, 40);      
        // 休眠1秒
        sleep(1);          
        // 进程1给管道的写端解锁
        lockf(fd[1], 0, 0);             
        exit(0);
    }
    else {
        // 创建进程2
        while ((pid2 = fork()) == -1);  

        // 如果是进程2在运行
        if (pid2 == 0) {     
            std::cout << "Child process 2 is working!" << std::endl;
            // 进程2给管道的写端上锁
            lockf(fd[1], 1, 0);             
            // 进程2往写空间中写入字符串
            sprintf(buffer, "Child process 2 is sending a message!");   
            // 进程2从写空间中读出40个字符放入管道中
            write(fd[1], buffer, 40);      
            // 休眠1秒
            sleep(1);        
            // 进程2给管道的写端解锁
            lockf(fd[1], 0, 0);            
            exit(0);
        }
        else {  // 如果是父进程执行
            std::cout << "Parent process is working!" << std::endl;
            // 读空间(存放从管道中读出的数据)
            char s[100];                    

            // 从管道中读出40个字符存入s中
            read(fd[0], s, 40);             
            std::cout << s << std::endl;

            // 从管道中读出40个字符存入s中
            read(fd[0], s, 40);             
            std::cout << s << std::endl;
            exit(0);
        }
    }

    return 0;
}

结果:

 

 分析:当父进程开始执行时,输出“Parent process is working!”,然后执行read(fd[0], s, 40)语句,由于此时fd中的字符数小于要求取出的字符数(40),会引起阻塞,此时操作系统进行进程调度,在该运行结果中,可以看到,操作系统为进程1分配处理机,进程1开始执行,输出“Child process 1 is working!”,当进程1执行完毕后,由于进程1已经向fd中写入了40个字符,此时父进程由阻塞变为就绪状态,操作系统进行进程调度,在本次运行结果中,可以看到,此时操作系统为父进程分配处理机,父进程开始执行,输出“Child process 1 is sending a message!”,然后再次执行read(fd[0], s, 40)语句,由于此时fd中的字符数仍小于要求取出的字符数(40),会引起阻塞,此时操作系统进行进程调度,为进程2分配处理机,进程2开始执行,输出“Child process 2 is working!”,待进程2执行完毕后,此时父进程由阻塞状态变为就绪状态,操作系统进行进程调度,将处理机分配给父进程,父进程开始执行,输出“Child process 2 is sending a message!”,执行完毕。


这一块其实需要查阅大量的资料才能理解,比如fd的作用,pipe()函数的作用、lockf()函数的作用等,我这里的注释简要写了下,如果不太能理解,可以查查具体函数的作用,来加以理解

  • 12
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈阿土i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值