有时需要等待……
newshound2
程序启用独立的进程运行rssgossip.py脚本,而子进程一创建就和父进程没关系了。rssgossip.py还没有完成任务,newshound2
程序就结束了,所以stories.txt还是空的。也就是说,操作系统必须提供一种方式,让你等待子进程完成任务。
waitpid()函数
waitpid()
函数会等子进程结束以后才返回,也就是说可以在程序中加几行代码,让它等到rssgossip.py脚本运行结束以后才退出。
waitpid()聚焦
waitpid()
接收三个参数:
pid
父进程在克隆子进程时会得到子进程的ID。
pid_status
pid_status
用来保存进程的退出信息。因为waitpid()
需要修改pid_status
,因此它必须是个指针。选项
waitpid()
有一些选项,详情可以输入man waitpid
查看。如果把选项设为0
,函数将等待进程结束。什么是pid_status?
waitpid()
函数结束等待时会在pid_status
中保存一个值,它告诉你进程的完成情况。为了得到子进程的退出状态,可以把pid_status
的值传给WEXITSTATUS()
宏:
为什么要用宏来查看?因为
pid_status
中保存了好几条信息,只有前8位表示进程的退出状态,可以用宏来查看这8位的值。
试驾
运行newshound2
程序,它会在退出前检查rssgossip.py脚本是否完成:
在程序中加入waitpid()
很容易办到,它可以让代码更加可靠。而在此之前无法确定子进程是否已经写完了文件,也就是说newshound2
并不是一个合格的工具,你无法在脚本中使用它,也无法为它创建界面。
重定向输入、输出,然后让进程相互等待,进程间通信就这么简单。一旦进程可以合作——通过共享数据和互相等待——它们将所向披靡。
要点
exit()
可以快速结束程序。所有打开的文件都记录在描述符表中。
通过修改描述符表就可以重定向输入和输出。
fileno()
能在表中查找描述符。
dup2()
可以用来修改描述符表。
waitpid()
等待进程结束。
这里没有蠢问题
问:用
exit()
来结束程序比从main()
返回更快吗?答:不会。但如果你已经调用了
exit()
,就不需要想办法让代码再回到main()
函数。在你调用exit()
的一瞬间,程序就升天了。问:为了防止调用失败,调用
exit()
时需要检查它的返回值是否为-1吗?答:不需要,
exit()
不会失败,因此也就没有返回值。exit()
是唯一没有返回值而且不会失败的函数。问:传给
exit()
的那个数字是退出状态吗?答:是的。
问:标准输入、标准输出和标准错误一定是描述符表的0、1、2号吗?
答:一定。
问:每当我打开一个新文件,它都会自动添加到描述符表中吗?
答:没错。
问:通常是几号描述符?
答:新文件总是按序加入描述符表,如果第一个空的描述符是4号,你的文件就会用它。
问:描述符表有多大?
答:从0号到255号。
问:描述符表那么麻烦,有必要用吗?
答:当然有,不使用描述符表,就不能改变程序的工作方式,也就不能重定向。
问:除了用标准输出,还有没有其他方法把数据发送到屏幕?
答:在一些系统上,比如Unix,如果打开/dev/tty文件,就可以把数据直接发送到终端。
问:我能用
waitpid()
等待其他进程吗?还是只有我启动的那些?答:你可以用
waitpid()
等待任何进程。问:为什么不能根据
wait_pid(…, &pid_status, …)
中的pid_status
直接判断退出状态?答:因为
pid_status
中还包含了其他信息。问:哪些信息?
答:如果一个进程自然死亡,
WIFSIGNALED(pid_status)
就为假,如果是他杀,WIFSIGNALED(pid_status)
就为真。问:
pid_status
明明是整型变量,怎么可以包含多条信息?答:用不同的位来保存不同的信息。
pid_status
的前8位保存了退出状态,而其他信息保存在了剩余那些位中。问:是不是只要自行提取出
pid_status
的前8位,就可以不用WEXITSTATUS()
?答:最好还是用
WEXITSTATUS()
,它不但可以提高代码的可读性,而且无论int
在你的平台上有多大,程序都能正确工作。问:为什么
WEXITSTATUS()
要大写?答:因为
WEXITSTATUS()
是宏,不是函数。编译器运行时会把宏替换为一小段代码。