fork, exec, and disown

Isaac To kkto at csis.hku.hk
Sun Feb 8 22:33:36 EST 2004


>>>>> "Benoit" == Benoit Dejean <bnet at ifrance.com> writes:

    Benoit> Le Sun, 08 Feb 2004 22:22:37 +0800, Isaac To a écrit :
    >> You can do that, but if you run ps you'll notice that all you
    >> processes get into a Z (zombie), <defunct> state.  Sooner or later
    >> you'll have the fork() giving you error that "resource temporarily
    >> not available" because all process numbers are used up.

    Benoit> you're right, i haven't noticed that

    >> With the "double fork" technique you can avoid this by adding a wait
    >> at the end:
    >> 
    >> def fork_exec_disown(cmd, dir="~"): if os.fork() == 0: if os.fork():
    >> sys.exit(0) os.chdir(os.path.expanduser(dir)) cmd = cmd.split()
    >> os.execvp(cmd[0], cmd) os.wait()

    Benoit> ok, i use this

    >> The wait will wait only for the child, not the grand-child.  If you
    >> don't have that you'll start accumulating zombies.  In some OS you
    >> can avoid the double forking overhead by manipulating the signal
    >> handler of SIGCHLD (so that it has the flag SA_NOCLDWAIT and has
    >> handler SIG_IGN), but that is more platform dependent than fork().

    Benoit> could you tell me more about that ?  because i am really
    Benoit> interested in. i want to have the best/fastest replacement for
    Benoit> os.system

E.g., in my Linux box, the following won't leave any zombie:

import os
import time
import signal
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
def fork_exec_disown(cmd, dir="~"):
    if os.fork() == 0:
        os.chdir(os.path.expanduser(dir))
        cmd = cmd.split()
        os.execvp(cmd[0], cmd)
for i in xrange(1000):
    fork_exec_disown("true")
time.sleep(100)

On the other hand, the effect is global, so once you do that you cannot
expect you can wait for process that have already been dead.  E.g., the
following no longer work:

>>> def f():
...     pid = os.fork()
...     if pid == 0:
...         os.execlp("true", "true")
...     time.sleep(1)
...     os.wait()
... 
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 6, in f
OSError: [Errno 10] No child processes

So double forking has its merits, since it is per-child rather than
per-parent.  And modern OS actually do fork() rather efficiently anyway.

Regards,
Isaac.



More information about the Python-list mailing list