bpo-36867: Create the resource_tracker before launching SharedMemoryManagers by pierreglaser · Pull Request #13276 · python/cpython
TLDR; The resource_tracker needs to be created before SharedMemoryManager processes are launched (which is not the case for managers created using fork)
Take this example below:
from multiprocessing.managers import SharedMemoryManager from multiprocessing import resource_tracker smm = SharedMemoryManager() smm.start() sl = smm.ShareableList(range(10)) smm.shutdown()
This simple and legitimate python scripts results in a very noisy output:
/home/pierreglaser/repos/cpython/Lib/multiprocessing/resource_tracker.py:198: UserWarning: resource_tracker: There appear to be 1 leaked shared_memory objects to clean up at shutdown warnings.warn('resource_tracker: There appear to be %d ' /home/pierreglaser/repos/cpython/Lib/multiprocessing/resource_tracker.py:211: UserWarning: resource_tracker: '/psm_3bfa242d': [Errno 2] No such file or directory: '/psm_3bfa242d' warnings.warn('resource_tracker: %r: %s' % (name, e))
Here is why it happens:
-
smm.start()launches a newmanagerprocess. At this point in the main process, noresource_trackeris created if themanageris launched usingfork. -
sl = smm.ShareableList(range(10))does two things:- First, it creates a new shared_memory object from the parent process. At creation, a
resource_tracker.registercall is done ->resource_tracker.ensure_runningis done -> a newresource_trackerprocess is created. In addition, thisresource_trackernow trackssl. However, since the manager process was created before, it does not know that a newresource_trackerprocess was just created in the parent process.. - Once
slis created, theSharedMemoryManagerasks itsSharedMemoryTracker( which lives in the manager process) to track it.
- First, it creates a new shared_memory object from the parent process. At creation, a
-
smm.shutdownshuts down the manager. It thus asks theSharedMemoryTrackerto destroysl, which it tracks. To do so,- it first opens it (using a
SharedMemory(name)) call, which itself triggers aresource_tracker.registercall ->resource_tracker.ensure_runningcall in the manager process, where no resource_tracker exists yet! Thus, anotherResourceTrackerinstance /process is created and starts trackingsl - immediatly after, it
unlinkssl. This sends anunregistercall to the newly createdresource_tracker.
- it first opens it (using a
When the script ends however, nothing has been done to tell the original resource_tracker created in the parent process that sl was properly unlinked. The resource_tracker thus thinks a leak happened, and tells the user (first line of my output)). However, there was no leak, as sl was properly unlinked by the manager. Therefore, the cleanup attempt of the resource_tracker fails, resulting the second error.
The solution to this problem is simply to create the right before the manager process is created.