Python互斥锁

Python互斥锁教程

锁的作用就是某个 线程 在访问某个资源时先锁住,防止其它线程的访问,等访问完毕解锁后其他线程再来加锁进行访问。

Python 的 threading 模块提供了 Lock 和 RLock 两个类,即互斥锁和递归锁。

死锁

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁。

死锁是锁的一种错误使用状态,编程过程中,不应出现死锁的情况。

互斥锁

每个资源都对应于一个可称为 “互斥锁” 的标记,这个标记用来保证在任意时刻,只能有一个线程访问该资源,其它的线程只能等待。

互斥锁是传统并发编程对共享资源进行访问控制的主要手段,在 Python 中,threading 模块提供了相关互斥锁的操作,互斥锁的操作主要涉及到两个操作,即 acquire 和 release。acquire 锁定当前的共享资源,release 进行解锁。

在使用互斥锁时,一定要注意:对资源操作完成后,一定要解锁,否则会出现流程执行异常,死锁等问题。

互斥锁使用详解

语法

from threading import Thread,Lock # 创建互斥锁 lock = threading.Lock() # 对需要访问的资源加锁 lock.acquire() # 资源访问结束解锁 lock.release()

说明

互斥锁的使用,需要使用 threading.Lock() 创建一个互斥锁对象,接着对需要加锁访问的资源使用 lock.acquire() 进行加锁即可,最后,资源访问结束,使用 lock.release() 进行解锁即可。

案例

互斥锁

使用 lock.acquire() 和 lock.release() 操作临界资源

import threading num = 0 # 创建互斥锁 lock = threading.Lock() def handler_incry(): global num for i in range(100000): num += 1 print("handler_incry done, num =", num) def handler_decry(): global num for i in range(100000): num -= 1 print("handler_decry done, num =", num) if __name__ == '__main__': print("嗨客网(www.haicoder.net)") # 创建线程 t1 = threading.Thread(target=handler_incry) t2 = threading.Thread(target=handler_decry) # 启动线程 t1.start() t2.start() t1.join() t2.join()

程序运行后,控制台输出如下:

09 python线程互斥锁.png

首先,我们定义了一个 int 类型的全局变量 num ,同时,我们使用 threading.Lock() 创建了一个互斥锁对象 lock。

接着,我们创建了一个 handler_incry 函数 和一个 handler_decry 函数,handler_incry 函数使用 for 循环 将全局变量 num 的值加 100000 次,执行完毕后,打印当前的 num 的值。

handler_decry 函数将全局变量 num 的减 100000 次,执行完毕后,打印当前的 num 的值,同时,我们创建了两个线程 t1 和 t2,他们的线程处理函数是我们上面定义的 handler_decryhandler_incry

最后,在 main 函数,我们开启了两个线程,并且使用 join 等待线程的结束。程序运行后,我们发现,程序的输出乱了,线程 t1 输出了一半,线程 t2 再次来输出了,这就是线程并发导致的问题。因此,我们修改程序为如下:

import threading num = 0 # 创建互斥锁 lock = threading.Lock() def handler_incry(): global num lock.acquire() for i in range(100000): num += 1 print("handler_incry done, num =", num) lock.release() def handler_decry(): global num lock.acquire() for i in range(100000): num -= 1 print("handler_decry done, num =", num) lock.release() if __name__ == '__main__': print("嗨客网(www.haicoder.net)") # 创建线程 t1 = threading.Thread(target=handler_incry) t2 = threading.Thread(target=handler_decry) # 启动线程 t1.start() t2.start() t1.join() t2.join()

程序运行,如下:

10 python线程互斥锁.png

我们修改程序,我们在对全局变量 num 进行增加之前使用了 lock.acquire() 进行了加锁,同时,在对变量 num 访问结束时,再次进行解锁,并且,在两个线程处理函数都使用了这个锁。

因此,现在,不管我们运行多少次我们的程序,最终的输出都不会再混乱,因为锁的存在,保证了永远只可能有一个线程在访问和操作全局变量,这样通过锁的机制,就保证了多线程访问共享资源的线程安全问题。

Python互斥锁教程总结

Python 的 threading 模块引入了互斥锁(Lock)。threading 模块提供了 Lock 和 RLock 两个类,即互斥锁和递归锁。python 互斥锁语法:

from threading import Thread,Lock # 创建互斥锁 lock = threading.Lock() # 对需要访问的资源加锁 lock.acquire() # 资源访问结束解锁 lock.release()