关于os.waitpid()返回值不是子进程的退出状态码
背景
写了一段代码,目的是父进程fork
出子进程,然后通过os.waitpid()
等待子进程执行结束,并且获取子进程退出的状态码。大致实例代码如下:
1 | import os |
然而这段代码执行过之后,明明子进程返回了99,但是发现父进程获取到的结果是25344。好像返回了一个不正确的状态码,这是怎么回事呢?
分析
通过查看Python的官方文档,可以得知,os.waitpid()
和 wait()
的返回值是一样的(其实还有好几个差不多的),那么看一下wait
方法的返回值,注意官方说法:
Wait for completion of a child process, and return a tuple containing its pid and exit status indication: a 16-bit number, whose low byte is the signal number that killed the process, and whose high byte is the exit status (if the signal number is zero); the high bit of the low byte is set if a core file was produced.
这类函数返回一个元组,第一个是我们等待的进程的pid,在本文中返回pid没有意义,因为我们是指定进程pid等待的,它只是把我们给定的入参又返回了(当然在其他例子里,也可以不指定某个具体的pid作为入参,这时候就有意义了,告诉你返回的进程具体是哪个)。
重点是第二个参数,这是一个编码过的数字,这个数字只有16位,低8位是杀死该子进程的信号编号,而高8位是退出状态(如果信号编号是0),其中低8位的最高位如果被置位,则表示产生了一个core文件。
结合文档,印证实例代码,可以发现我们返回值99正好对应25344,因为99 * 256 = 25344,说明99正好在第二字节上。
解决
看到这里就知道了,其实只要把返回的第二个参数,从中提取出我们要的子进程的exitcode即可。
因为返回都是正数或者0,所以解决方案没那么复杂。首先要知道低8位都是0,前面低8位的值是255,那么实际上可以这么写:
1 | _, exitcode = os.waitpid(pid, 0) |
因此最后只要这么写就可以了:
1 | _, exitcode = os.waitpid(pid, 0) |
虽然代码随便写都能成功,但是有两点请注意:
- Python的整数长度是不限制的
- 虽然说计算退出状态码不涉及高位溢出,但是要知道有这个东西,具体请看补码的内容
参考
https://docs.python.org/2/library/os.html