互斥锁
一.概念原理
当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制
线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。
互斥锁为资源引入一个状态:锁定/非锁定。
某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
二.示例
from threading import Thread
from threading import Lock
g_num = 0
#创建一个全局锁对象
lock= Lock()
def work1(num):
global g_num
lock.acquire()#加锁
for i in range(num):
g_num+=1
lock.release()#解锁
print("in work1-->",g_num)
def work2(num):
global g_num
lock.acquire()#加锁
for i in range (num):
g_num+=1
lock.release()#解锁
print("work2-->",g_num)
def main():
t1 = Thread(target=work1,args=(1000000,))
t2 = Thread(target=work2, args=(1000000,))
t1.start()
t2.start()
t2.join()
if __name__ == '__main__':
main()
print("main-->",g_num)
结果:
in work1--> 1000000
work2--> 2000000
main--> 2000000
其中,
锁定方法acquire可以有一个参数。
如果参数设定为True,则当前线程会堵塞,直到获取到这个锁为止(如果没有指定,那么默认为True)
如果设定参数为False,则当前线程不会堵塞
锁的好处:
确保了某段关键代码只能由一个线程从头到尾完整地执行
锁的坏处:
阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁
死锁
一.概念
在多道程序系统中,由于多个进程的并发执行,改善了系统资源的利用率并提高了系统的处理能力。
然而,多个进程的并发执行也带来了新的问题——死锁。所谓死锁是指多个进程因竞争资源而造成的一种僵局,若无外力作用,这些进程都将无法向前推进。
二.示例
lock1 = Lock()
lock2 = Lock()
def work1(num):
lock1.acquire()#lock1上锁
time.sleep(1)
print("in work1")
lock2.acquire() # lock2上锁
print("work1-----")
lock2.release()#lock2解锁
lock1.release()#lock1解锁
def work2(num):
lock2.acquire()#lock2加锁
print("in work2")
lock1.acquire()#lock1加锁
print("work1-----")
lock1.release()#lock1解锁
lock2.release()#lock2解锁
if __name__ == '__main__':
t1 = Thread(target=work1,args=(1000000,))
t2 = Thread(target=work2, args=(1000000,))
t1.start()
t2.start()
结果:
in work2
in work1
看了上面的例子我们来说说防止死锁的加锁机制
问题:
你正在写一个多线程程序,其中线程需要一次获取多个锁,此时如何避免死锁问题。
解决方案:
在多线程程序中,死锁问题很大一部分是由于线程同时获取多个锁造成的。举个例子:一个线程获取了第一个锁,然后在获取第二个锁的 时候发生阻塞,那么这个线程就可能阻塞其他线程的执行,从而导致整个程序假死。 解决死锁问题的一种方案是为程序中的每一个锁分配一个唯一的id,然后只允许按照升序规则来使用多个锁。