问题
最近在写UNP书上关于pipe和fifo关于进程间通信的例子的时候,遇到了一些问题。
书上是一个父进程fork出一个子进程,然后父进程执行client(), 子进程执行server(),最后父进程调用waitpid()等待子进程的结束。
为什么不是父进程执行server(),子进程client()呢?关键点在于client、server由哪个进程执行和是否执行waitpid会影响程序的正常运行。在调换client、server的情况下,子进程无法顺利结束,而且父进程也会因此阻塞在waitpid中。
原因
server()的作用是等待client()发送来的文件名,打开相应文件并发文件内容发给client(),由client()打印出文件内容。从逻辑上看,server()会先于client()结束。
另外client()调用read读取server()发送过来的文件内容,read()系统调用会在读到EOF时返回0,而pipe、fifo是利用写引用计数来判断当前写端数量的,并且会在写引用计数为0时,使得read读到EOF,从而返回0,结束等待。
使用fork创建进程时,pipe打开的读写端会同时在父子进程可用,即会增加引用计数,因此在fork后在父子进程上都需要先关闭不需要的读写端口。
综上,当父进程执行server,子进程执行client时,父进程先于子进程执行完毕,然后阻塞在waitpid等待子进程结束;而子进程则调用read将文件读取打印后阻塞等待read返回0,即等待父进程关闭写端口;此时陷入死锁,两个进程都无法结束。
而调换顺序后,父进程执行client,子进程执行server,子进程先执行完毕,终止后系统自动关闭子进程打开的读写pipe、fifo端口,并发送EOF符号,此时父进程读取并打印完后,read读到EOF返回0,父进程结束client,执行waitpid等待子进程终止,并顺利退出并结束。
解决方法
1. 调换server、client
2. 执行server进程,退出server后,主动关闭写端口
3. 参考- 参考二
1 |
|