互斥锁
互斥锁的概念:
互斥锁:对共享数据进行锁定,保证同一时刻只能有一个线程去操作。
注意:互斥锁是多个线程一起去抢,抢到锁的线程先执行,没有抢到锁的线程需要等待,等互斥锁使用完释放后,其它等待的线程再去抢这个锁。
互斥锁的使用
threading模块中定义了Lock变量,这个变量本质上是一个函数,通过调用这个函数可以获取一把互斥锁。
互斥锁使用步骤:
# 创建锁
mutex = threading.Lock()
# 上锁
mutex.acquire()
-----这里内容只保证同一时刻只能有一个线程去操作,对共享数据进行锁定
# 释放锁
mutex.release()
注意点:
- acquire和release方法之间的代码同一时刻只能存在一个线程去操作
- 如果再调用acquire方法的时候 其他线程已经使用了这个互斥锁,那么这个时候acquire会堵塞,直到这个互斥锁释放后才能再次上锁。
使用互斥锁完成2个线程对同一个全局变量各加100万次的操作
import threading
# 定义全局变量
g_num = 0
# 创建全局互斥锁
lock = threading.Lock()
# 循环一次给 全局变量加1
def sum_nu1():
# 上锁
lock.acquire()
for i in range(1000000):
global g_num
g_num += 1
# 循环一次给全局变量加1
def sum_num2():
# 上锁
lock.acquire()
for i in range(1000000):
global g_num
g_num += 1
print('sum2:', g_num)
# 释放锁
if __name__ == '__main__':
# 创建两个线程
first_thread = threading.Thread(target=sum_num1)
second_thread = threading.Thread(target=sum_num2)
# 启动线程
first_thread.start()
second_thread.start()
# 加上互斥锁,那个线程抢到这个锁我们决定不了,那线程抢到锁那个线程先执行,没有抢到的线程需要等待。
# 加上互斥锁多任务瞬间变成单任务,性能会下降,也就是说同一时刻只能有一个线程去执行
执行结果
sum1:1000000
sum2:2000000
-
为什么要用互斥锁??
互斥锁能够保证多个线程访问共享数据不会出现数据报错问题 -
互斥锁的作用?
互斥锁作用就是保证同一时刻只能有一个线程去操作共享数据,保证共享数据不会出现错误问题 -
互斥锁的好处??
确保某段关键代码只能由一个线程从头到尾完整地去执行 -
互斥锁的影响??
使用互斥锁会影响代码的执行效率,多任务改成单任务执行 -
如果没有使用好互斥锁会发什么??
没有使用好任意出现死锁的情况
条件变量为什么要和互斥锁配合使用
互斥锁一个明显的缺点是他只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,他常和互斥锁一起使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程会先被阻塞,然后解开互斥锁,等待条件变量发生变化。一旦其他的某个线程改变了条件变量,会发出一个signal通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。一般说来,条件变量被用来进行线承间的同步。
总结:条件变量用在某个线程需要在某种条件才去保护它将要操作的临界区的情况下,从而避免了线程不断轮询检查该条件是否成立而降低效率的情况,这是实现了效率提高