I need to detect if the PID of a grandchild process is alive. Because the multiprocessing.Process() object is non-pickleable (for security reasons), I can't pass it up the process hierarchy and call process.is_alive()
so I need to pass the PID and use that instead.
The following code successfully identifies that the PID is active however when I manually kill the process (in Ubuntu using kill
in bash) it erroneously continues detecting it as active. process.is_alive()
on the other hand works correctly. How can I reliably detect PID state using only the PID?
import os
import time
from multiprocessing import Process
def pid_is_alive(pid):
try:
os.kill(pid, 0) # Send signal 0 to check if the process exists.
except ProcessLookupError:
return False
return True
def worker():
print("worker started")
print(os.getpid())
while True:
time.sleep(1)
print("worker running")
p = Process(target=worker)
p.start()
while True:
time.sleep(1)
# Check if the PID is alive
if pid_is_alive(p.pid):
print(f'PID {p.pid} is alive.')
else:
print(f'PID {p.pid} is not alive.')
# if p.is_alive():
# print("Process is alive")
# else:
# print("Process is not alive")
Actually, the program behaves correctly.
When you kill the process, it goes to the defunct (a.k.a. zombie) state until its parent does a wait()
. In that time the PID is still in use and the is_alive()
returns True
- as you see, a more descriptive name would be PID_exists()
.
There are several options:
fork
technique to orphan the child process. The PID 1 process will become a new parent and will wait
for it. This is the easiest option IMO - if you don't care losing the exit status.