1
实验要求
使用 UNIX 系统调用编写一个程序 pingpong ,在一对管道上实现两个进程之间的通信。父进程应该通过第一个管道给子进程发送一个信息 "ping",子进程接收父进程的信息后打印 "<pid>: received ping"
,其中是其进程 ID 。然后子进程通过另一个管道发送一个信息 "pong" 给父进程,父进程接收子进程的信息然后打印 "<pid>: received pong"
,然后退出。
2
实验提示
- 使用
pipe
创建管道。 - 使用
fork
创建一个子进程。 - 使用
read
从管道读取信息,使用 write
将信息写入管道。 - 使用
getpid
获取当前 进程 ID
。 - 将程序添加到
Makefile
中的 UPROGS
。 - xv6 上的用户程序具有有限的库函数可供它们使用。你可以在
user/user.h
中查看,除系统调用外其他函数代码位于 user/ulib.c
、user/printf.c
、和 user/umalloc.c
中。
3
实验思路
- 首先引入头文件
kernel/types.h
和 user/user.h
。 - 开始编写
main
函数,定义两个文件描述符 ptoc_fd
和 ctop_fd
数组,创建两个管道, pipe(ptoc_fd)
和 pipe(ctop_fd)
,一个用于父进程传递信息给子进程,另一个用于子进程传递信息给父进程。pipe(pipefd)
系统调用会创建管道,并把读取和写入的文件描述符返回到 pipefd
中。pipefd[0]
指管道的读取端, pipefd[1]
指管道的写入端。可以使用命令 man pipe
查看手册获取更多内容。 - 创建缓冲区字符数组,存放传递的信息。
- 使用
fork
创建子进程,子进程的 fork
返回值为 0 ,父进程的 fork
返回子进程的 进程 ID
,所以通过 if 语句就能让父进程和子进程执行不同的代码块。 - 编写父进程执行的代码块。使用
write()
系统调用传入三个参数,把字符串 "ping"
写入管道一,第一个参数为管道的写入端文件描述符,第二个参数为写入的字符串,第三个参数为写入的字符串长度。然后调用 wait()
函数等待子进程完成操作后退出,传入参数 0 或者 NULL ,不过后者需要引入头文件 stddef.h
。使用 read()
系统调用传入三个参数,接收从管道二传来的信息,第一个参数为管道的读取端文件描述符,第二个参数为缓冲区字符数组,第三个参数为读取的字符串长度。最后调用 printf()
函数打印当前进程 ID 以及接收到的信息,即缓冲区的内容。 - 编写子进程执行的代码块。使用
read()
系统调用传入三个参数,接收从管道一传来的信息,第一个参数为管道的读取端文件描述符,第二个参数为缓冲区字符数组,第三个参数为读取的字符串长度。然后调用 printf()
函数打印当前进程 ID 以及接收到的信息,即缓冲区的内容。最后使用 write()
系统调用传入三个参数,把字符串 "pong"
写入管道二,第一个参数为管道的写入端文件描述符,第二个参数为写入的字符串,第三个参数为写入的字符串长度。 - 最后调用
exit()
系统调用使程序正常退出。
4
实验代码
// Lab Xv6 and Unix utilities
// pingpong.c
#include "kernel/types.h"
#include "user/user.h"
#include "stddef.h"
int
main(int argc, char *argv[])
{
int ptoc_fd[2], ctop_fd[2];
pipe(ptoc_fd);
pipe(ctop_fd);
char buf[8];
if (fork() == 0) {
// child process
read(ptoc_fd[0], buf, 4);
printf("%d: received %s\n", getpid(), buf);
write(ctop_fd[1], "pong", strlen("pong"));
}
else {
// parent process
write(ptoc_fd[1], "ping", strlen("ping"));
wait(NULL);
read(ctop_fd[0], buf, 4);
printf("%d: received %s\n", getpid(), buf);
}
exit(0);
}
5
实验结果
在 Makefile
文件中, UPROGS
项追加一行 $U/_pingpong\
。编译并运行 xv6 进行测试。
$ make qemu
...
init: starting sh
$ pingpong
4: received ping
3: received pong
$
退出 xv6 ,运行单元测试检查结果是否正确。
./grade-lab-util pingpong
通过测试样例。
make: 'kernel/kernel' is up to date.
== Test pingpong == pingpong: OK (1.1s)