| 23 | |
| 24 | @contextmanager |
| 25 | def acquire(*locks): |
| 26 | # Sort locks by object identifier |
| 27 | locks = sorted(locks, key=lambda x: id(x)) |
| 28 | |
| 29 | # Make sure lock order of previously acquired locks is not violated |
| 30 | acquired = getattr(_local,'acquired',[]) |
| 31 | if acquired and max(id(lock) for lock in acquired) >= id(locks[0]): |
| 32 | raise RuntimeError('Lock Order Violation') |
| 33 | |
| 34 | # Acquire all of the locks |
| 35 | acquired.extend(locks) |
| 36 | _local.acquired = acquired |
| 37 | |
| 38 | try: |
| 39 | for lock in locks: |
| 40 | lock.acquire() |
| 41 | yield |
| 42 | finally: |
| 43 | # Release locks in reverse order of acquisition |
| 44 | for lock in reversed(locks): |
| 45 | lock.release() |
| 46 | del acquired[-len(locks):] |
| 47 | |
| 48 | x_lock = threading.Lock() |
| 49 | y_lock = threading.Lock() |