Weird behaviour with threads and processes mixing
<p>I'm running the following python code:</p>

<pre><code>import threading
import multiprocessing

def forever_print():
    while True:
        print("")

def main():
    t = threading.Thread(target=forever_print)
    t.start()
    return


if __name__=='__main__':
    p = multiprocessing.Process(target=main)
    p.start()
    p.join()
    print("main process on control")
</code></pre>

<p>It terminates. </p>

<p>When I unwrapped <code>main</code> from the new process, and just ran it directly, like this:</p>

<pre><code>if name == '__main__':
    main()
</code></pre>

<p>The script went on forever, as I thought it should. Am I wrong to assume that, given that <code>t</code> is a non-daemon process, <code>p</code> shouldn't halt in the first case?</p>

<p>I basically set up this little test because i've been developing an app in which threads are spawned inside subprocesses, and it's been showing some weird behaviour (sometimes it terminates properly, sometimes it doesn't). I guess what I wanted to know, in a broader sense, is if there is some sort of "gotcha" when mixing these two python libs.</p>

<p>My running environment: python 2.7 @ Ubuntu 14.04 LTS</p>

<p>The gotcha is that the <code>multiprocessing</code> machinery calls <a href="https://docs.python.org/2/library/os.html#os._exit" rel="nofollow"><code>os._exit()</code></a> after your target function exits, which violently kills the child process, even if it has background threads running.</p>

<p>The code for <code>Process.start()</code> looks like this:</p>

<pre><code>def start(self):
    '''
    Start child process
    '''
    assert self._popen is None, 'cannot start a process twice'
    assert self._parent_pid == os.getpid(), \
           'can only start a process object created by current process'
    assert not _current_process._daemonic, \
           'daemonic processes are not allowed to have children'
    _cleanup()
    if self._Popen is not None:
        Popen = self._Popen
    else:
        from .forking import Popen
    self._popen = Popen(self)
    _current_process._children.add(self)
</code></pre>

<p><code>Popen.__init__</code> looks like this:</p>

<pre><code>        def __init__(self, process_obj):
        sys.stdout.flush()
        sys.stderr.flush()
        self.returncode = None

        self.pid = os.fork()  # This forks a new process
        if self.pid == 0: # This if block runs in the new process
            if 'random' in sys.modules:
                import random
                random.seed()
            code = process_obj._bootstrap()  # This calls your target function
            sys.stdout.flush()
            sys.stderr.flush()
            os._exit(code)  # Violent death of the child process happens here
</code></pre>

<p>The _bootstrap method is the one that actually executes the <code>target</code> function you passed passed to the <code>Process</code> object. In your case, that's <code>main</code>. <code>main</code> returns right after you start your background thread, even though the <em>process</em> doesn't exit, because there's still a non-daemon thread running.</p>

<p>However, as soon execution hits <code>os._exit(code)</code>, the child process is killed, regardless of any non-daemon threads still executing.</p>

python multithreading multiprocessing