🌸小白白系列第五弹~🌸
*写在前面🌟:Hi~everybody😄
本失踪人口回归,最近一直在忙各种考试👻,实在分身乏术😣,又不想水文章,想一直坚持写高质量好文💪,故而今日考试一结束,我就来更新了🙌!嘿嘿,希望大家喜欢哦😉
目录
🍀前言:🍀
**
🌻🌻🌻按照惯例,在实验前,我们需要先了解一些基本知识~
**
🍀【实验资料】:
🌻一、小白发问:什么是管道呢🤓?
🌷🌷🌷所谓管道,是指能够连接一个写进程和一个读进程的、并允许它们以生产者—消费者方式进行通信的一个共享文件,又称为pipe文件。由写进程从管道的写入端(句柄1)将数据写入管道,而读进程则从管道的读出端(句柄0)读出数据。
**不懂的,懒的读的,直接看下图🐷**
~
🌻二、那么管道都有哪些类型呢🤔
****🍁1.有名管道 ****
一个可以在文件系统中
长期存在
的、具有路径名的文件。用系统调用mknod( )
建立。它克服无名管道使用上的局限性,可让更多的进程也能利用管道进行通信
。因而其它进程可以知道它的存在,并能利用路径名来访问该文件
。对有名管道的访问方式与访问其他文件一样,需先用open( )打开。
****🍁2.无名管道 ****
一个
临时文件
。利用pipe( )建立
起来的无名文件(无路径名)。只用该系统调用所返回的文件描述符来标识该文件,故只有调用pipe( )的进程及其子孙进程才能识别此文件描述符,
才能利用该文件(管道)进行通信。当这些进程不再使用此管道时,核心收回其索引结点。二种管道的读写方式是相同的,本次实验使用无名管道。
🌻三、实验涉及的系统调用👀
🍁1.pipe( )创建无名管道 ****
建立一无名管道。
系统调用格式
pipe(filedes)
参数定义
int pipe(filedes)
;
int filedes[2]
;
其中,filedes[1]是写入端,filedes[0]是读出端
。
该函数使用头文件如下:
#include <unistd.h>
#inlcude <signal.h>
#include <stdio.h>
🍁2.lockf 文件锁 ***
lockf()函数允许
将文件区域用作信号量(监视锁
),或用于控制对锁定进程的访问(强制模式记录锁定
)。试图访问已锁定资源的其他进程将返回错误或进入休眠状态,直到资源解除锁定为止。当关闭文件时,将释放进程的所有锁定,即使进程仍然有打开的文件。当进程终止时,将释放进程保留的所有锁定。 头文件: #include <unistd.h>
详见实验四的必读材料
~
🍁3.read( ) ***
系统调用格式
read( fd ,buf ,nbyte )
功能:从fd
(一般是fd[0])所指示的文件中读出nbyte个字节
的数据
,并将它们送至由指针buf所指示的缓冲区中
。如该文件被加锁,等待,直到锁打开为止。
🍁4.write( ) ***
系统调用格式
write(fd,buf,nbyte)
功能:把nbyte 个字节的数据
,从buf所指向的缓冲区写到由fd(一般是fd[1])所指向的文件中
。如文件加锁,暂停写入,直至开锁。
—————————————————————————
***提示***:以下是本篇文章正文内容,下面我们将会通过三个例子学习管道通信,本文案例可供参考(直接ctrl+C/V到作业嘿嘿~🌝🌝)***
☀正文:🌙🌝
🍀【实验目的】:
🍂1.了解管道的概念。
🍂2.掌握Linux支持的管道通信方式。
🍀【实验内容】:
🌹🌹🌹一、 编写一段程序,实现进程的管道通信:
使用pipe()建立一个管道。子进程p1向管道写一句话:
Child process is sending message!
而父进程则从管道中读取来自于子进程的信息,显示在屏幕上。
1、参考代码:🌛
#include<signal.h>
#include<sys/wait.h>
# include<unistd.h>
# include<stdio.h>
# include<stdlib.h>
#include<sys/wait.h>
#include<sys/types.h>
int pid1; //存储子进程的PID号;
int main()
{
int fd[2]; //打开文件的文件描述符
char OutPipe[100],InPipe[100];//存储要写入管道的字符串
pipe(fd); //创建无名管道
while((pid1 = fork()) == -1);//先pipe再fork,创建了2个管道
if(pid1 == 0)
{
sprintf(OutPipe,"Child process is sending message!");//将字符串存储outpipe里
write(fd[1],OutPipe,50);//将50个字节的数据从outpipe写入到fd[1]端
sleep(1); //休眠1秒,防止读写冲突
exit(0);//安全及时的退出
}
else //父进程
{
wait(0); //等待子进程
read(fd[0],InPipe,50);//将50个字节的数据从fd[0]中读出到inpipe里
printf("%s\n",InPipe); //打印inpipe内字符串
}
return 0;
}
2、运行结果:🌜
yzy@yzy-virtual-machine:~/new$ ./aa.out
Child process is sending message!
**3、分析结果:**⭐⭐⭐
(1)过程:
使用pipe函数创建一个管道,让子进程向管道中写入一句话:Child process is sending message!”而父进程从管道中读出这句话,并显示在屏幕上。
(2)解释
sprintf函数作用:
打印到字符串中
(要注意字符串的长度要足够容纳打印的内容,否则会出现内存溢出),而printf函数打印输出到屏幕上。sprintf函数在我们完成其他数据类型转换成字符串类型的操作中应用广泛。**
🌹🌹🌹二、编写一段程序,实现父子进程间的管道通信。
使用pipe()建立一条管道线。两个子进程p1和p2分别向管道各写一句话:
Child 1 is sending message!
Child 2 is sending message!
而父进程则从管道中分别读出来自于两个子进程的信息,显示在屏幕上。
1、参考代码:🌛🐟🐟🌜🌛🌝
# include<unistd.h>
# include<signal.h>
# include<stdio.h>
# include<stdlib.h>
#include<sys/wait.h>
#include<sys/types.h>
int pid1,pid2; //存储两个子进程的PID号;
int main()
{
int fd[2]; //打开文件的文件描述符
char OutPipe[100],InPipe[100]; //存储要写入管道的字符串
pipe(fd);//创建无名管道
while((pid1=fork())==-1); //用fork函数创建子进程
if(pid1==0){ //子进程1号
lockf(fd[1],1,0); //上锁,为了两个子进程之间的互斥
sprintf(OutPipe,"Child process 2 is sending a message!"); //存储字符串
write(fd[1],OutPipe,50);//将字符串写入管道
sleep(1); //休眠1秒,防止写冲突
lockf(fd[1],0,0); //解锁,与上锁成对使用
exit(0);//安全退出
}
else{
while((pid2=fork())==-1); //子进程2号,同上
if(pid2==0){
lockf(fd[1],1,0);
sprintf(OutPipe,"Child process 1 is sending a message!");
write(fd[1],OutPipe,50);
sleep(1);
lockf(fd[1],0,0);
exit(0);}
else{ //父进程
read(fd[0],InPipe,50); //将字符串1从管道中读出到inpipe
printf("%s\n",InPipe); //打印inpipe内数据
wait(0); //等待子进程
read(fd[0],InPipe,50); //将字符串2从管道中读出到inpipe
printf("%s\n",InPipe);
exit(0);
}
}
return 0;
}
2、运行结果:🌜🌜🌛🐠🐠
yzy@yzy-virtual-machine:~/new$ ./2a.out
Child process 2 is sending a message!
Child process 1 is sending a message!
**3、分析结果:**⭐⭐⭐⭐
根据阅读材料: 读/写进程互斥,为使读、写进程互斥地访问pipe文件,需使各进程互斥地访问pipe文件索引结点中的直接地址项。因此,每次进程在访问pipe文件前,都需检查该索引文件是否已被上锁。若是,进程便睡眠等待,否则,将其上锁,进行读/写。操作结束后解锁,并唤醒因该索引结点上锁而睡眠的进程。根据上述材料,编写代码,先打出一个父进程,两个子进程,一条管道线的框架。再加上互斥锁,sleep函数,wait函数等,防止两个子进程互斥。
🌹🌹🌹三、编写一段程序,实现:在父进程中用pipe()建立一条管道,往管道里写入两句话(字符串),两个子进程分别接收来自父进程写入的两句话并打印输出。
****1、参考代码:**🌛🌛🌛🌛🌛
# include<unistd.h>
# include<signal.h>
# include<stdio.h>
# include<stdlib.h>
#include<sys/wait.h>
#include<sys/types.h>
int pid1,pid2; //存储两个子进程的PID号;
int main()
{
int fd[2]; //打开文件的文件描述符
char OutPipe[100],InPipe[100]; //存储要写入管道的字符串
pipe(fd); //创建无名管道
while((pid1=fork())==-1); //用fork函数创建子进程
if(pid1==0){ //子进程1号
read(fd[0],InPipe,50); //将字符串1从管道中读出到inpipe
printf("%s\n",InPipe); //打印inpipe内数据
}
else{
while((pid2=fork())==-1); //子进程2号,同上
if(pid2==0){
read(fd[0],InPipe,50); //将字符串2从管道中读出到inpipe
printf("%s\n",InPipe);
exit(0);}
else{ //父进程
lockf(fd[1],1,0); //上锁,为了两个子进程之间的互斥
sprintf(OutPipe,"Child process 2 is reading a message from pipe!"); //存储字符串
write(fd[1],OutPipe,50);//将字符串2写入管道
sleep(1); //休眠1秒,防止写冲突
lockf(fd[1],0,0); //解锁,与上锁成对使用
wait(0);
lockf(fd[1],1,0); //同上
sprintf(OutPipe,"Child process 1 is reading a message from pipe!");
write(fd[1],OutPipe,50); //将字符串1写入管道
sleep(1);
lockf(fd[1],0,0);
exit(0);
}
}
return 0;}
2、运行结果: **🌜🌛🌜🌜🌜
y@yzy-virtual-machine:~/new$ ./3a.out
Child process 2 is reading a message from pipe!
Child process 1 is reading a message from pipe!
**3、分析结果:****⭐⭐⭐⭐⭐
本题与上题不同,是由
父进程写入管道
,子进程读出内容
,这是一种单向通信
。
代码编写思路:
第一步-创建管道
。
第二步-创建子进程
。
第三步-父进程写入管道
。
第四步-子进程从管道中读取信息并写入标准输出
。
第五步-再一次重复第三步和第四步
。
🍀【实验感想】:
**1、🌟⭐管道通信的特点:**⭐🌟
(1)
管道是半双工的,先进先出的,它把一个进程的输出和另一个进程的输入连接在一起
(2)一个进程(写进程)在管道的尾部写入数据,另一个进程(读进程)从管道的头部读出数据
**2、🌟⭐无名管道作用:**🌟⭐
用于父子进程之间的通信。创建管道——读管道——写管道——关闭管道。管道用于不同进程间的通信,通常先创建一个管道,在通过fork函数创建一个子进程,该子进程会继承父进程所创建的管道
。
***喜欢的朋友可以留下你的赞哦~***