@@ -3793,13 +3793,6 @@ def test_shared_memory_basics(self):
3793
3793
self .assertIn (sms .name , str (sms ))
3794
3794
self .assertIn (str (sms .size ), str (sms ))
3795
3795
3796
- # Test pickling
3797
- sms .buf [0 :6 ] = b'pickle'
3798
- pickled_sms = pickle .dumps (sms )
3799
- sms2 = pickle .loads (pickled_sms )
3800
- self .assertEqual (sms .name , sms2 .name )
3801
- self .assertEqual (bytes (sms .buf [0 :6 ]), bytes (sms2 .buf [0 :6 ]), b'pickle' )
3802
-
3803
3796
# Modify contents of shared memory segment through memoryview.
3804
3797
sms .buf [0 ] = 42
3805
3798
self .assertEqual (sms .buf [0 ], 42 )
@@ -3898,6 +3891,29 @@ class OptionalAttachSharedMemory(shared_memory.SharedMemory):
3898
3891
3899
3892
sms .close ()
3900
3893
3894
+ def test_shared_memory_recreate (self ):
3895
+ # Test if shared memory segment is created properly,
3896
+ # when _make_filename returns an existing shared memory segment name
3897
+ with unittest .mock .patch (
3898
+ 'multiprocessing.shared_memory._make_filename' ) as mock_make_filename :
3899
+
3900
+ NAME_PREFIX = shared_memory ._SHM_NAME_PREFIX
3901
+ names = ['test01_fn' , 'test02_fn' ]
3902
+ # Prepend NAME_PREFIX which can be '/psm_' or 'wnsm_', necessary
3903
+ # because some POSIX compliant systems require name to start with /
3904
+ names = [NAME_PREFIX + name for name in names ]
3905
+
3906
+ mock_make_filename .side_effect = names
3907
+ shm1 = shared_memory .SharedMemory (create = True , size = 1 )
3908
+ self .addCleanup (shm1 .unlink )
3909
+ self .assertEqual (shm1 ._name , names [0 ])
3910
+
3911
+ mock_make_filename .side_effect = names
3912
+ shm2 = shared_memory .SharedMemory (create = True , size = 1 )
3913
+ self .addCleanup (shm2 .unlink )
3914
+ self .assertEqual (shm2 ._name , names [1 ])
3915
+
3916
+ def test_invalid_shared_memory_cration (self ):
3901
3917
# Test creating a shared memory segment with negative size
3902
3918
with self .assertRaises (ValueError ):
3903
3919
sms_invalid = shared_memory .SharedMemory (create = True , size = - 1 )
@@ -3910,6 +3926,41 @@ class OptionalAttachSharedMemory(shared_memory.SharedMemory):
3910
3926
with self .assertRaises (ValueError ):
3911
3927
sms_invalid = shared_memory .SharedMemory (create = True )
3912
3928
3929
+ def test_shared_memory_pickle_unpickle (self ):
3930
+ sms = shared_memory .SharedMemory (create = True , size = 512 )
3931
+ self .addCleanup (sms .unlink )
3932
+ sms .buf [0 :6 ] = b'pickle'
3933
+
3934
+ # Test pickling
3935
+ pickled_sms = pickle .dumps (sms )
3936
+ self .assertNotIn (b'pickle' , pickled_sms )
3937
+
3938
+ # Test unpickling
3939
+ sms2 = pickle .loads (pickled_sms )
3940
+ self .assertIsInstance (sms2 , sms .__class__ )
3941
+ self .assertEqual (sms .name , sms2 .name )
3942
+ self .assertEqual (bytes (sms .buf [0 :6 ]), bytes (sms2 .buf [0 :6 ]), b'pickle' )
3943
+
3944
+ # Test that unpickled version is still the same SharedMemory
3945
+ sms .buf [0 :6 ] = b'newval'
3946
+ self .assertEqual (bytes (sms .buf [0 :6 ]), bytes (sms2 .buf [0 :6 ]), b'newval' )
3947
+
3948
+ sms2 .buf [0 :6 ] = b'oldval'
3949
+ self .assertEqual (bytes (sms .buf [0 :6 ]), bytes (sms2 .buf [0 :6 ]), b'oldval' )
3950
+
3951
+ def test_shared_memory_pickle_unpickle_dead_object (self ):
3952
+ sms = shared_memory .SharedMemory (create = True , size = 512 )
3953
+ sms .buf [0 :6 ] = b'pickle'
3954
+ pickled_sms = pickle .dumps (sms )
3955
+
3956
+ # Now, we are going to kill the original object.
3957
+ # So, unpickled one won't be able to attach to it.
3958
+ sms .close ()
3959
+ sms .unlink ()
3960
+
3961
+ with self .assertRaises (FileNotFoundError ):
3962
+ pickle .loads (pickled_sms )
3963
+
3913
3964
def test_shared_memory_across_processes (self ):
3914
3965
# bpo-40135: don't define shared memory block's name in case of
3915
3966
# the failure when we run multiprocessing tests in parallel.
@@ -4132,11 +4183,9 @@ def test_shared_memory_ShareableList_pickling(self):
4132
4183
4133
4184
serialized_sl = pickle .dumps (sl )
4134
4185
deserialized_sl = pickle .loads (serialized_sl )
4135
- self .assertTrue (
4136
- isinstance (deserialized_sl , shared_memory .ShareableList )
4137
- )
4138
- self .assertTrue (deserialized_sl [- 1 ], 9 )
4139
- self .assertFalse (sl is deserialized_sl )
4186
+ self .assertIsInstance (deserialized_sl , shared_memory .ShareableList )
4187
+ self .assertEqual (deserialized_sl [- 1 ], 9 )
4188
+ self .assertIsNot (sl , deserialized_sl )
4140
4189
deserialized_sl [4 ] = "changed"
4141
4190
self .assertEqual (sl [4 ], "changed" )
4142
4191
@@ -4145,12 +4194,24 @@ def test_shared_memory_ShareableList_pickling(self):
4145
4194
larger_sl = shared_memory .ShareableList (range (400 ))
4146
4195
self .addCleanup (larger_sl .shm .unlink )
4147
4196
serialized_larger_sl = pickle .dumps (larger_sl )
4148
- self .assertTrue (len (serialized_sl ) == len (serialized_larger_sl ))
4197
+ self .assertEqual (len (serialized_sl ), len (serialized_larger_sl ))
4149
4198
larger_sl .shm .close ()
4150
4199
4151
4200
deserialized_sl .shm .close ()
4152
4201
sl .shm .close ()
4153
4202
4203
+ def test_shared_memory_ShareableList_pickling_dead_object (self ):
4204
+ sl = shared_memory .ShareableList (range (10 ))
4205
+ serialized_sl = pickle .dumps (sl )
4206
+
4207
+ # Now, we are going to kill the original object.
4208
+ # So, unpickled one won't be able to attach to it.
4209
+ sl .shm .close ()
4210
+ sl .shm .unlink ()
4211
+
4212
+ with self .assertRaises (FileNotFoundError ):
4213
+ pickle .loads (serialized_sl )
4214
+
4154
4215
def test_shared_memory_cleaned_after_process_termination (self ):
4155
4216
cmd = '''if 1:
4156
4217
import os, time, sys
@@ -4202,7 +4263,7 @@ def test_shared_memory_cleaned_after_process_termination(self):
4202
4263
"shared_memory objects to clean up at shutdown" , err )
4203
4264
4204
4265
#
4205
- #
4266
+ # Test to verify that `Finalize` works.
4206
4267
#
4207
4268
4208
4269
class _TestFinalize (BaseTestCase ):
0 commit comments