A Serializable per-process Lock This wraps a normal ``threading.Lock`` object and satisfies the same interface. However, this lock can also be serialized and sent to different processes. It will not block concurrent operations between processes (for this you should look at ``multi
| 1280 | |
| 1281 | |
| 1282 | class SerializableLock: |
| 1283 | """A Serializable per-process Lock |
| 1284 | |
| 1285 | This wraps a normal ``threading.Lock`` object and satisfies the same |
| 1286 | interface. However, this lock can also be serialized and sent to different |
| 1287 | processes. It will not block concurrent operations between processes (for |
| 1288 | this you should look at ``multiprocessing.Lock`` or ``locket.lock_file`` |
| 1289 | but will consistently deserialize into the same lock. |
| 1290 | |
| 1291 | So if we make a lock in one process:: |
| 1292 | |
| 1293 | lock = SerializableLock() |
| 1294 | |
| 1295 | And then send it over to another process multiple times:: |
| 1296 | |
| 1297 | bytes = pickle.dumps(lock) |
| 1298 | a = pickle.loads(bytes) |
| 1299 | b = pickle.loads(bytes) |
| 1300 | |
| 1301 | Then the deserialized objects will operate as though they were the same |
| 1302 | lock, and collide as appropriate. |
| 1303 | |
| 1304 | This is useful for consistently protecting resources on a per-process |
| 1305 | level. |
| 1306 | |
| 1307 | The creation of locks is itself not threadsafe. |
| 1308 | """ |
| 1309 | |
| 1310 | _locks: ClassVar[WeakValueDictionary[Hashable, Lock]] = WeakValueDictionary() |
| 1311 | token: Hashable |
| 1312 | lock: Lock |
| 1313 | |
| 1314 | def __init__(self, token: Hashable | None = None): |
| 1315 | self.token = token or str(uuid.uuid4()) |
| 1316 | if self.token in SerializableLock._locks: |
| 1317 | self.lock = SerializableLock._locks[self.token] |
| 1318 | else: |
| 1319 | self.lock = Lock() |
| 1320 | SerializableLock._locks[self.token] = self.lock |
| 1321 | |
| 1322 | def acquire(self, *args, **kwargs): |
| 1323 | return self.lock.acquire(*args, **kwargs) |
| 1324 | |
| 1325 | def release(self, *args, **kwargs): |
| 1326 | return self.lock.release(*args, **kwargs) |
| 1327 | |
| 1328 | def __enter__(self): |
| 1329 | self.lock.__enter__() |
| 1330 | |
| 1331 | def __exit__(self, *args): |
| 1332 | self.lock.__exit__(*args) |
| 1333 | |
| 1334 | def locked(self): |
| 1335 | return self.lock.locked() |
| 1336 | |
| 1337 | def __getstate__(self): |
| 1338 | return self.token |
| 1339 |
no outgoing calls
searching dependent graphs…