1717import socket
1818import random
1919import logging
20+ import subprocess
2021import struct
2122import operator
2223import pickle
@@ -3765,6 +3766,27 @@ def test_shared_memory_SharedMemoryServer_ignores_sigint(self):
37653766
37663767 smm .shutdown ()
37673768
3769+ @unittest .skipIf (os .name != "posix" , "resource_tracker is posix only" )
3770+ def test_shared_memory_SharedMemoryManager_reuses_resource_tracker (self ):
3771+ # bpo-36867: test that a SharedMemoryManager uses the
3772+ # same resource_tracker process as its parent.
3773+ cmd = '''if 1:
3774+ from multiprocessing.managers import SharedMemoryManager
3775+
3776+
3777+ smm = SharedMemoryManager()
3778+ smm.start()
3779+ sl = smm.ShareableList(range(10))
3780+ smm.shutdown()
3781+ '''
3782+ rc , out , err = test .support .script_helper .assert_python_ok ('-c' , cmd )
3783+
3784+ # Before bpo-36867 was fixed, a SharedMemoryManager not using the same
3785+ # resource_tracker process as its parent would make the parent's
3786+ # tracker complain about sl being leaked even though smm.shutdown()
3787+ # properly released sl.
3788+ self .assertFalse (err )
3789+
37683790 def test_shared_memory_SharedMemoryManager_basics (self ):
37693791 smm1 = multiprocessing .managers .SharedMemoryManager ()
37703792 with self .assertRaises (ValueError ):
@@ -3904,8 +3926,6 @@ def test_shared_memory_ShareableList_pickling(self):
39043926 sl .shm .close ()
39053927
39063928 def test_shared_memory_cleaned_after_process_termination (self ):
3907- import subprocess
3908- from multiprocessing import shared_memory
39093929 cmd = '''if 1:
39103930 import os, time, sys
39113931 from multiprocessing import shared_memory
@@ -3916,18 +3936,29 @@ def test_shared_memory_cleaned_after_process_termination(self):
39163936 sys.stdout.flush()
39173937 time.sleep(100)
39183938 '''
3919- p = subprocess .Popen ([sys .executable , '-E' , '-c' , cmd ],
3920- stdout = subprocess .PIPE )
3921- name = p .stdout .readline ().strip ().decode ()
3939+ with subprocess .Popen ([sys .executable , '-E' , '-c' , cmd ],
3940+ stdout = subprocess .PIPE ,
3941+ stderr = subprocess .PIPE ) as p :
3942+ name = p .stdout .readline ().strip ().decode ()
39223943
3923- # killing abruptly processes holding reference to a shared memory
3924- # segment should not leak the given memory segment.
3925- p .terminate ()
3926- p .wait ()
3927- time .sleep (1.0 ) # wait for the OS to collect the segment
3944+ # killing abruptly processes holding reference to a shared memory
3945+ # segment should not leak the given memory segment.
3946+ p .terminate ()
3947+ p .wait ()
3948+ time .sleep (1.0 ) # wait for the OS to collect the segment
39283949
3929- with self .assertRaises (FileNotFoundError ):
3930- smm = shared_memory .SharedMemory (name , create = False )
3950+ # The shared memory file was deleted.
3951+ with self .assertRaises (FileNotFoundError ):
3952+ smm = shared_memory .SharedMemory (name , create = False )
3953+
3954+ if os .name == 'posix' :
3955+ # A warning was emitted by the subprocess' own
3956+ # resource_tracker (on Windows, shared memory segments
3957+ # are released automatically by the OS).
3958+ err = p .stderr .read ().decode ()
3959+ self .assertIn (
3960+ "resource_tracker: There appear to be 1 leaked "
3961+ "shared_memory objects to clean up at shutdown" , err )
39313962
39323963#
39333964#
@@ -4560,7 +4591,7 @@ def run_in_child(cls):
45604591 print (json .dumps (flags ))
45614592
45624593 def test_flags (self ):
4563- import json , subprocess
4594+ import json
45644595 # start child process using unusual flags
45654596 prog = ('from test._test_multiprocessing import TestFlags; ' +
45664597 'TestFlags.run_in_child()' )
@@ -4866,7 +4897,6 @@ def test_resource_tracker(self):
48664897 #
48674898 # Check that killing process does not leak named semaphores
48684899 #
4869- import subprocess
48704900 cmd = '''if 1:
48714901 import time, os, tempfile
48724902 import multiprocessing as mp
0 commit comments