进程的管道通信
1)使用系统调用pipe()建立一条管道,系统调用fork()分别创建两个子进程,它们分别向管道写一句话,如:
Child process1 is sending a message!
Child process2 is sending a message!
2) 父进程分别从管道读出来自两个子进程的信
息,显示在屏幕上。
3) 两个子进程要并发执行。
4) 实现管道的互斥使用。当一个子进程正在对管道进行写操作时,另一个欲写入管道的子进程必须等待。 使用系统调用lockf(fd[1],1,0)实现对管道的加锁操作,用lockf(fd[1],0,0)解除对管道的锁定。
5) 实现父子进程的同步,当父进程试图从一空管道中读取数据时,便进入等待状态,直到子进程将数据写入管道返回后,才将其唤醒。
### 进程管道通信知识点详解
#### 一、实验背景与目标
本实验旨在通过具体的编程实践,加深学生对进程间通信(IPC)机制之一——管道通信的理解,并掌握其具体实现方法。实验主要目的是:
1. **理解进程概念**:区分进程与程序,了解进程的生命周期及其基本属性。
2. **学习进程创建**:熟悉`fork()`系统调用创建新进程的过程。
3. **进程并发执行现象**:分析多进程并行执行时的资源争用问题,以及如何使用互斥机制解决这些问题。
4. **解决进程同步问题**:了解如何实现进程间的同步,特别是在管道通信中的应用。
5. **掌握管道通信技术**:重点学习Linux系统中利用管道实现进程间通信的具体方法。
#### 二、实验内容与要求
实验要求实现以下功能:
1. **管道建立与使用**:利用`pipe()`系统调用创建一个管道,再通过`fork()`创建两个子进程,每个子进程向管道写入一段消息。
2. **父子进程通信**:父进程从管道读取子进程写入的消息,并在屏幕上显示这些消息。
3. **并发执行子进程**:确保两个子进程能够并发执行,即在一个子进程写入消息的同时,另一个子进程可以准备写入或等待。
4. **互斥访问管道**:为了防止多个进程同时写入管道导致的数据混乱,需要实现管道的互斥访问。这通常通过`lockf()`系统调用来实现。
5. **进程间的同步**:实现父子进程间的同步机制,确保父进程在尝试从空管道读取数据时会进入等待状态,直到有子进程向管道写入数据。
#### 三、程序实现
##### 1. 数据结构及变量定义
- `int fd[2]`:定义了一个管道,其中`fd[0]`用于读取,`fd[1]`用于写入。
- `char bufread[75], bufwrite[75]`:定义了读写缓冲区,用于存储管道中传输的信息。
##### 2. 主函数与关键步骤
```c
int main() {
int fd[2], p1, p2, r;
char bufread[75], bufwrite[75];
// 创建管道
pipe(fd);
// 创建子进程1
while ((p1 = fork()) == -1) {
printf("\nChild process one is failed!\n");
}
if (p1 == 0) {
// 子进程1的逻辑
lockf(fd[1], 1, 0); // 对管道加锁
strcpy(bufwrite, "Child process one is sending message!");
write(fd[1], bufwrite, strlen(bufwrite)); // 向管道写入信息
sleep(5); // 子进程1睡眠
lockf(fd[1], 0, 0); // 管道解锁
exit(0); // 子进程1结束
} else {
// 创建子进程2
while ((p2 = fork()) == -1) {
printf("\nChild process two is failed!\n");
}
if (p2 == 0) {
// 子进程2的逻辑
lockf(fd[1], 1, 0); // 对管道加锁
strcpy(bufwrite, "Child process two is sending message!");
write(fd[1], bufwrite, strlen(bufwrite)); // 向管道写入信息
sleep(5); // 子进程2睡眠
lockf(fd[1], 0, 0); // 管道解锁
exit(0); // 子进程2结束
}
}
// 父进程读取信息
read(fd[0], bufread, 75);
printf("Message from child process one: %s\n", bufread);
read(fd[0], bufread, 75);
printf("Message from child process two: %s\n", bufread);
return 0;
}
```
##### 3. 关键系统调用解释
- **`pipe()`**:创建一个管道。返回值为一个整型数组,其中`fd[0]`用于读取,`fd[1]`用于写入。
- **`fork()`**:创建一个新的进程,返回值表示当前进程是父进程还是子进程。
- **`lockf(fd[1], 1, 0)`**:对管道进行加锁,防止其他进程同时写入。
- **`lockf(fd[1], 0, 0)`**:解除对管道的锁定,允许其他进程写入。
- **`write(fd[1], bufwrite, 75)`**:将信息写入管道。
- **`read(fd[0], bufread, 75)`**:从管道读取信息。
#### 四、总结
通过以上实验,我们不仅深入了解了进程间通信的基本原理和技术细节,还实际操作了如何利用管道来实现进程间的通信。此外,实验还涉及了进程并发执行、进程间同步等问题的解决方案,这些都是现代操作系统设计中非常重要的概念和技术。通过此类实验的学习与实践,有助于深入理解操作系统的核心机制,提高解决实际问题的能力。