你需要对多线程程序中的临界区加锁以避免竞争条件。例如只有一台打印机,但却有两个以上的输入程序,这个时候打印机就是竞争资源。
如何解决,给打印机上锁,使用打印机时上锁,使用完解锁。
在python中使用 threading 库中的 Lock 对象
用with语句,更加方便,自动获取锁,自动释放,这样可以避免忘记释放
下面看例子:
import threading
import time
import random
class PrintTest:
def __init__(self):
self.lock_value=threading.Lock()
def print_001(self):
while True:
time.sleep(random.randint(1,4))
with self.lock_value:
print("001号正在使用打印机")
def print_002(self):
while True:
time.sleep(random.randint(1, 4))
with self.lock_value:
print("002号正在使用打印机")
if __name__=='__main__':
p=PrintTest()
t1=threading.Thread(target=p.print_001)
t2=threading.Thread(target=p.print_002)
t1.setDaemon(True)
t2.setDaemon(True)
t1.start()
t2.start()
t1.join()
t2.join()
print("done")
运行结果:
001号正在使用打印机
002号正在使用打印机
002号正在使用打印机
002号正在使用打印机
001号正在使用打印机
002号正在使用打印机
001号正在使用打印机
002号正在使用打印机
002号正在使用打印机
002号正在使用打印机
001号正在使用打印机
顺便介绍一下可重入锁:
在 threading 库中还提供了其他的同步原语,比如 RLock 和 Semaphore 对象。但是根据以往经验,这些原语是用于一些特殊的情况,如果你只是需要简单地对可变对象进行锁定,那就不应该使用它们。一个 RLock (可重入锁)可以被同一个线程多次获取,主要用来实现基于监测对象模式的锁定和同步。在使用这种锁的情况下,当锁被持有时,只有一个线程可以使用完整的函数或者类中的方法。比如,你可以实现一个这样的 SharedCounter 类:
import threading
class SharedCounter:
'''
A counter object that can be shared by multiple threads.
'''
_lock = threading.RLock()
def __init__(self, initial_value = 0):
self._value = initial_value
def incr(self,delta=1):
'''
Increment the counter with locking
'''
with SharedCounter._lock:
self._value += delta
def decr(self,delta=1):
'''
Decrement the counter with locking
'''
with SharedCounter._lock:
self.incr(-delta)