@@ -70,8 +70,9 @@ class SharedMemory:
7070 _flags = os .O_RDWR
7171 _mode = 0o600
7272 _prepend_leading_slash = True if _USE_POSIX else False
73+ _track_resource = True
7374
74- def __init__ (self , name = None , create = False , size = 0 ):
75+ def __init__ (self , name = None , create = False , size = 0 , track_resource = True ):
7576 if not size >= 0 :
7677 raise ValueError ("'size' must be a positive integer" )
7778 if create :
@@ -81,6 +82,7 @@ def __init__(self, name=None, create=False, size=0):
8182 if name is None and not self ._flags & os .O_EXCL :
8283 raise ValueError ("'name' can only be None if create=True" )
8384
85+ self ._track_resource = track_resource
8486 if _USE_POSIX :
8587
8688 # POSIX Shared Memory
@@ -108,6 +110,7 @@ def __init__(self, name=None, create=False, size=0):
108110 self ._name = name
109111 try :
110112 if create and size :
113+ size += _posixshmem .REFCOUNT_SIZE
111114 os .ftruncate (self ._fd , size )
112115 stats = os .fstat (self ._fd )
113116 size = stats .st_size
@@ -116,8 +119,13 @@ def __init__(self, name=None, create=False, size=0):
116119 self .unlink ()
117120 raise
118121
119- from .resource_tracker import register
120- register (self ._name , "shared_memory" )
122+ self ._size = size
123+ self ._refcount = memoryview (self ._mmap )[0 :_posixshmem .REFCOUNT_SIZE ]
124+ self ._buf = memoryview (self ._mmap )[_posixshmem .REFCOUNT_SIZE :]
125+
126+ if self ._track_resource :
127+ from .resource_tracker import register
128+ register (self .name , "shared_memory" )
121129
122130 else :
123131
@@ -176,8 +184,9 @@ def __init__(self, name=None, create=False, size=0):
176184 size = _winapi .VirtualQuerySize (p_buf )
177185 self ._mmap = mmap .mmap (- 1 , size , tagname = name )
178186
179- self ._size = size
180- self ._buf = memoryview (self ._mmap )
187+ self ._size = size
188+ self ._buf = memoryview (self ._mmap )
189+ self ._refcount = None
181190
182191 def __del__ (self ):
183192 try :
@@ -215,11 +224,17 @@ def name(self):
215224 @property
216225 def size (self ):
217226 "Size in bytes."
218- return self ._size
227+ if _USE_POSIX :
228+ return self ._size - _posixshmem .REFCOUNT_SIZE
229+ else :
230+ return self ._size
219231
220232 def close (self ):
221233 """Closes access to the shared memory from this instance but does
222234 not destroy the shared memory block."""
235+ if self ._refcount is not None :
236+ self ._refcount .release ()
237+ self ._refcount = None
223238 if self ._buf is not None :
224239 self ._buf .release ()
225240 self ._buf = None
@@ -237,10 +252,25 @@ def unlink(self):
237252 called once (and only once) across all processes which have access
238253 to the shared memory block."""
239254 if _USE_POSIX and self ._name :
240- from .resource_tracker import unregister
241255 _posixshmem .shm_unlink (self ._name )
242- unregister (self ._name , "shared_memory" )
243-
256+ if self ._track_resource :
257+ from .resource_tracker import unregister
258+ unregister (self .name , "shared_memory" )
259+
260+ def cleanup_shared_memory (name ):
261+ try :
262+ shm = SharedMemory (name , track_resource = False )
263+ refcount = _posixshmem .shm_dec_refcount (shm ._refcount )
264+ if refcount == 0 : shm .unlink ()
265+ except FileNotFoundError : # Segment with name has already been unlinked
266+ pass
267+
268+ def shm_inc_refcount (name ):
269+ try :
270+ shm = SharedMemory (name , track_resource = False )
271+ _posixshmem .shm_inc_refcount (shm ._refcount )
272+ except FileNotFoundError : # Segment with name has already been unlinked
273+ pass
244274
245275_encoding = "utf8"
246276
0 commit comments