在多线程中,当多个线程同时处理一个共享资源(如文件)时(向文件中读写数据),为了避免并发修改错误(多个线程访问同一资源导致数据不一致),使用了某种锁定机制,当一个线程访问一个资源时,它会锁定该资源,直到它释放该锁定,其他线程都不能访问同一资源。
锁对象:Python 多线程
在 Python 的threading
模块中,为了高效多线程,使用了一个原语锁。这个锁帮助我们同步两个或多个线程。锁类可能提供了 Python 中最简单的同步原语。
原始锁可以有两种状态:锁定或解锁,并且最初是在我们初始化 lock 对象时在解锁状态下创建的。它有两种基本方法,acquire()
和release()
。
以下是创建锁对象的基本语法:
import threading
threading.Lock()
锁对象使用两种方法,它们是:
acquire(blocking=True, timeout=-1)
方法
此方法用于获取锁。当它在没有参数的情况下被调用时,它会一直阻塞,直到锁被解锁。
该方法可以采用 2 个可选参数,它们是:
- 阻塞标志,如果该锁已经被某个其他线程获得,则该标志如果作为
False
发送,将不会阻塞该线程,并将作为结果返回False
。如果您将该阻塞标志的值提供为True
,那么如果其他线程持有锁,调用线程将被阻塞,一旦锁被释放,那么您的线程将获得锁并返回True
。 - timeout 参数用于提供一个正浮点值,该值指定如果其他线程正在持有锁,调用线程将被阻塞的秒数。默认值为 -1 表示如果线程不能立即获得锁,它将被无限期阻塞。
release()
方法
它用于释放获取的锁。如果锁被锁定,这个方法会将其重置为解锁状态,然后返回。此外,该方法可以从任何线程调用。
当调用此方法时,已经等待获取锁的线程中的一个被允许持有锁。
此外,如果在未锁定的锁上调用它,它会抛出RuntimeError
。
是时候举个例子了!
下面我们有一个简单的 python 程序,其中我们有一个类SharedCounter
,它将作为线程之间的共享资源。
我们有一个task
方法,我们称之为increment()
方法。由于多个线程将访问同一个计数器并增加其值,因此存在并发修改的可能性,这可能导致counter
的值不一致。
请始终从上面的代码中获取:
- 当一个线程使用
acquire()
方法获取锁,然后访问一个资源时,如果在访问资源的过程中出现了一些错误,会怎么样?在这种情况下,没有其他线程能够访问该资源,因此我们必须访问try
块内的资源。在finally
区块内部,我们可以调用release()
方法来重新锁定。 - 尝试注释第 13 行和第 19 行的代码,并尝试多次运行代码,有时您会看到代码会给出正确的输出,但有时您会看到不正确的
counter
值。