Using my PR 7827, the following command shows a leak of 4 Windows handles per run: python -m test -R 3:3 test_multiprocessing_spawn -v -m test.test_multiprocessing_spawn.WithProcessesTestPool.test_traceback See also bpo-33929: test_multiprocessing_spawn: WithProcessesTestProcess.test_many_processes() leaks 5 handles on Windows.
* Pool._repopulate_pool() creates processes with args=(self._inqueue, ...) * Pool._inqueue is a multiprocessing.queues.SimpleQueue * Process.__init__() of multiprocessing.popen_spawn_win32 calls reduction.dump(process_obj, to_child) which indirectly contains the SimpleQueue * A SimpleQueue object contains: self._reader, self._writer = connection.Pipe(duplex=False) * dump() indirectly calls reduce_connection() (ex: for SimpleQueue._reader) of multiprocessing.connection * reduce_connection() duplicates the pipe handle It's unclear to me who is supposed to close the duplicated pipe handles? reduce_connection() creates a "ds = resource_sharer.DupSocket(s)" object, but this object doesn't seem to call CloseHandle()?
> * dump() indirectly calls reduce_connection() (ex: for SimpleQueue._reader) of multiprocessing.connection > * reduce_connection() duplicates the pipe handle Sorry, it's reduce_pipe_connection(), not reduce_connection(). > It's unclear to me who is supposed to close the duplicated pipe handles? reduce_connection() creates a "ds = resource_sharer.DupSocket(s)" object, but this object doesn't seem to call CloseHandle()? reduce_pipe_connection() creates a DupHandle object which duplicates the handle, and it's detach() method closes the handle. The race condition is that sometimes the pool terminates a worker (worker() function of multiprocessing.pool) before the worker has time to close the duplicated handle. The handle is closed by: * rebuild_pipe_connection() * dh.detach(), extract: return _winapi.DuplicateHandle( proc, self._handle, _winapi.GetCurrentProcess(), self._access, False, _winapi.DUPLICATE_CLOSE_SOURCE)