33import time
44import typing
55from contextlib import closing
6-
76from multiprocessing .shared_memory import SharedMemory
87
98__all__ = ["PLock" , "SharedBytes" ]
@@ -44,12 +43,20 @@ class PLock:
4443 """
4544
4645 DEFAULT_SIZE = 4 # 4 bytes, means 2^32 = 4GB
47- DEFAULT_BYTEORDER = "little"
48-
49- def __init__ (self , name : str , force = False , close_atexit = False , pid = None ):
46+ DEFAULT_BYTEORDER : typing .Literal ["little" , "big" ] = "little"
47+
48+ def __init__ (
49+ self ,
50+ name : str ,
51+ force = False ,
52+ close_atexit = False ,
53+ pid = None ,
54+ force_signum : typing .Optional [int ] = None ,
55+ ):
5056 self .name = name
5157 self .pid = pid or os .getpid ()
5258 self .force = force
59+ self .force_signum = force_signum
5360 self .shm = None
5461 # whether the shared memory is closed
5562 self ._closed = False
@@ -60,16 +67,43 @@ def __init__(self, name: str, force=False, close_atexit=False, pid=None):
6067 raise RuntimeError (f"Failed to create shared memory { name } " )
6168
6269 @staticmethod
63- def wait_for_free (name : str , timeout = 3 , interval = 0.1 ):
70+ def is_free (name : str ) -> bool :
71+ """Check if the shared memory is free."""
72+ try :
73+ with closing (SharedMemory (name = name )):
74+ return False
75+ except FileNotFoundError :
76+ return True
77+
78+ @classmethod
79+ def kill_with_name (cls , name : str , sig_num = 15 ):
80+ """Kill the process that holds the shared memory."""
81+ if cls .is_free (name ):
82+ return False
83+ else :
84+ with closing (SharedMemory (name = name )) as shm :
85+ mem_pid = int .from_bytes (
86+ shm .buf [: cls .DEFAULT_SIZE ], byteorder = cls .DEFAULT_BYTEORDER
87+ )
88+ try :
89+ os .kill (mem_pid , sig_num )
90+ return True
91+ except ProcessLookupError :
92+ return False
93+
94+ @classmethod
95+ def wait_for_free (cls , name : str , timeout = 3 , interval = 0.1 ):
6496 """Wait for the shared memory to be free."""
6597 start = time .time ()
66- while time .time () - start < timeout :
67- try :
68- SharedMemory (name = name ).close ()
69- time .sleep (interval )
70- except FileNotFoundError :
98+ while True :
99+ free = cls .is_free (name )
100+ if free :
71101 return True
72- return False
102+ elif time .time () - start > timeout :
103+ return False
104+ else :
105+ time .sleep (interval )
106+ continue
73107
74108 def init (self ):
75109 if self ._closed :
@@ -79,7 +113,10 @@ def init(self):
79113 self .shm = SharedMemory (name = self .name , create = True , size = self .DEFAULT_SIZE )
80114 except FileExistsError :
81115 self .shm = SharedMemory (name = self .name )
82- if not self .force :
116+ if self .force :
117+ if self .force_signum is not None :
118+ ok = self .kill_with_name (self .name , sig_num = self .force_signum )
119+ else :
83120 ok = False
84121 if not ok :
85122 mem_pid = self .mem_pid
0 commit comments