异常飞出去,锁还在不在
(每道题开头都有同一段:上面那几样。)
贯穿全条的几样东西:
Counter / SafeCounter 读-睡-写的计数器;Safe 版用 with self.lock 包住三步(conc_03 的写法)
hammer(counter, workers, times) 开几条线程各加 times 次,交回最终的 n(真线程,题里只比大小)
probe(lock) 这把锁现在能不能立刻拿到(acquire(blocking=False),拿到就放回)——用它「看」锁的状态,不卡住
Guard(lock) 手写的 with 替身:__enter__ 拿、__exit__ 放两种写法各让临界区里抛一次异常,看异常之后锁是不是放开了:
import threading
import time
class Counter:
def __init__(self):
self.n = 0
def inc(self):
tmp = self.n
time.sleep(0.001)
self.n = tmp + 1
class SafeCounter(Counter):
def __init__(self):
super().__init__()
self.lock = threading.Lock()
def inc(self):
with self.lock:
tmp = self.n
time.sleep(0.001)
self.n = tmp + 1
def hammer(counter, workers=2, times=30):
def job():
for _ in range(times):
counter.inc()
ts = [threading.Thread(target=job) for _ in range(workers)]
for t in ts:
t.start()
for t in ts:
t.join()
return counter.n
def probe(lock):
"""这把锁现在能不能立刻拿到?能就拿了再放回去,交回 True;拿不到交回 False。"""
if lock.acquire(blocking=False):
lock.release()
return True
return False
class Guard:
"""手写的 with 替身:进就 acquire,出就 release——不管是正常出还是异常出。"""
def __init__(self, lock):
self.lock = lock
def __enter__(self):
self.lock.acquire()
return self
def __exit__(self, exc_type, exc, tb):
self.lock.release()
return False
def by_with(lock):
with lock:
raise ValueError("坏了")
def by_hand(lock):
lock.acquire()
raise ValueError("坏了")
lock.release()
res = []
for fn in (by_with, by_hand):
L = threading.Lock()
try:
fn(L)
except ValueError:
pass
res.append(str(probe(L)))
print("/".join(res))
全部评论