管道通信实践:子进程向父进程传递字符串

5星 · 超过95%的资源 需积分: 47 22 下载量 198 浏览量 更新于2024-09-11 收藏 45KB DOC 举报
"子进程通过管道将字符串‘hello!\n’传给父进程并显示” 在计算机编程中,特别是在多进程通信领域,父子进程间的通信是一个关键的环节。本示例中,子进程通过管道(pipe)将字符串"hello!\n"传递给父进程并显示,这涉及到操作系统提供的进程间通信(IPC)机制。以下将详细解析这个过程涉及的知识点: 一、管道通信 1. `pipe`系统调用 管道是一种半双工的通信方式,允许数据在一个方向上传输。`pipe()`函数用于创建一个无名管道。它接受一个整数数组`fd[2]`作为参数,返回时`fd[0]`是读端,`fd[1]`是写端。如果成功创建,函数返回0,失败则返回-1,并设置`errno`变量。 发送数据时,子进程使用`write()`函数,例如`write(fd[1], buf, size)`,将缓冲区`buf`中的`size`长度的字符串写入管道的写入端`fd[1]`。而接收数据的进程,如父进程,则使用`read()`函数,如`read(fd[0], bufa, size)`,从管道的读取端`fd[0]`读取数据到`bufa`缓冲区。 2. `sprintf`函数 `sprintf`是C语言中的一个格式化输出函数,它能将格式化后的数据写入指定的缓冲区。例如,在此示例中,子进程使用`sprintf(buf_in, "hello!\n")`将字符串"hello!\n"写入`buf_in`缓冲区,准备通过管道发送。 示例代码: ```c #include <unistd.h> #include <stdio.h> int main() { int x, fd[2]; char buf_in[80], buf_out[80]; pipe(fd); while ((x = fork()) == -1); // 创建子进程 if (x == 0) { // 子进程 sprintf(buf_in, "hello!\n"); write(fd[1], buf_in, sizeof(buf_in)); // 将字符串写入管道 exit(0); } else { // 父进程 wait(0); // 等待子进程结束 read(fd[0], buf_out, 80); // 从管道读取数据 printf("%s", buf_out); // 显示接收到的字符串 } } ``` 二、消息通信 虽然这个示例没有使用消息队列,但值得一提的是,消息队列是另一种进程间通信方式。与管道不同,消息队列支持异步通信,且消息具有独立性。每个消息队列通过一个关键字`key`标识,用户在创建时指定。消息队列允许进程发送特定结构的消息,并可以控制消息的接收顺序。 总结: 本示例展示了如何在父子进程中使用管道进行通信,子进程通过`sprintf`格式化字符串后写入管道,父进程则从管道读取数据并打印。这种通信方式在多进程程序设计中非常常见,特别是在需要数据交换的场景下。同时,管道和消息队列都是Linux等操作系统提供的高效、灵活的进程间通信机制。
2012-07-18 上传
1. 实验目的 1) 加深对进程概念的理解,明确进程和程序的区别。 2) 进一步认识并发执行的实质。 3) 分析进程争用资源的现象,学习解决进程互斥的方法。 4) 学习解决进程同步的方法。 5) 了解Linux系统中进程通信的基本原理。   进程是操作系统中最重要的概念,贯穿始终,也是学习现代操作系统的关键。通过本次实验,要求理解进程的实质和进程管理的机制。在Linux系统下实现进程从创建到终止的全过程,从中体会进程的创建过程、父进程和子进程之间的关系、进程状态的变化、进程之间的互斥、同步机制、进程调度的原理和以管道为代表的进程间的通信方式的实现。 2. 内容及要求:   这是一个设计型实验,要求自行编制程序。   使用系统调用pipe()建立一条管道,两个子进程分别向管道写一句话:   Child process1 is sending a message!   Child process2 is sending a message!   父进程从管道读出来自两个子进程的信息,显示在屏幕上。   要求: 1) 父进程先接收子进程1发来的消息,然后再接收子进程2发来的消息。 2) 实现管道的互斥使用,当一个子进程正在对管道进行写操作时,另一子进程必须等待。使用系统调用lockf(fd[1],1,0)实现对管道的加锁操作,用lockf(fd[1],0,0)解除对管道的锁定。 3) 实现父子进程的同步,当子进程把数据写入管道后,便去睡眠等待;当父进程试图从一空管道中读取数据时,也应等待,直到子进程将数据写入管道后,才将其唤醒。 3.相关的系统调用 1) fork() 用于创一个子进程。 格式:int fork(); 返回值:在子进程中返回0;在父进程中返回所创建的子进程的ID值;当返回-1时,创建失败。 2) wait() 常用来控制父进程与子进程的同步。 在父进程中调用wait(),则父进程被阻塞,进入等待队列,等待子进程结束。当子进程结束时,父进程从wait()返回继续执行原来的程序。 返回值:大于0时,为子进程的ID值;等于-1时,调用失败。 3) exit() 是进程结束时最常调用的。 格式:void exit( int status); 其中,status为进程结束状态。 4) pipe() 用于创建一个管道 格式:pipe(int fd); 其中fd是一个由两个数组元素fd[0]和fd[1]组成的整型数组,fd[0]是管道的读端口,用于从管道读出数据,fd[1] 是管道的写端口,用于向管道写入数据。 返回值:0 调用成功;-1 调用失败。 5) sleep() 调用进程睡眠若干时间,之后唤醒。 格式:sleep(int t); 其中t为睡眠时间。 6) lockf() 用于对互斥资源加锁和解锁。在本实验中,该调用的格式为: lockf(fd[1],1,0);/* 表示对管道的写入端口加锁。 lockf(fd[1],0,0);/* 表示对管道的写入端口解锁。 7) write(fd[1],String,Length) 将字符串String的内容写入管道的写入口。 8) read(fd[0],String,Length) 从管道的读入口读出信息放入字符串String中。 4.程序流程 父进程: 1) 创建管道; 2) 创建子进程1; 3) 创建子进程2; 4) 等待从管道中读出子进程1写入的数据,并显示在屏幕上; 5) 等待从管道中读出子进程2写入的数据,并显示在屏幕上; 6) 退出。 子进程: 1) 将管道的写入口加锁; 2) 将信息“Child process n is sending message!”输入到变量OutPipe中,n=1,2; 3) 将OutPipe中信息写入管道; 4) 睡眠等待; 5) 将管道的写入口解锁; 6) 退出。