记录于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()函数的作用等,我这里的注释简要写了下,如果不太能理解,可以查查具体函数的作用,来加以理解