Python Threads - Critical Section
什么是线程的"临界区"(在 Python 中)?
A thread enters the critical section
by calling the acquire() method, which
can either be blocking or
non-blocking. A thread exits the
critical section, by calling the
release() method.
- 理解 Python 中的线程,Linux Gazette
另外,锁的用途是什么?
其他人给出了非常好的定义。这是经典的例子:
1 2 3 4 5 6 7 8 9 | import threading account_balance = 0 # The"resource" that zenazn mentions. account_balance_lock = threading.Lock() def change_account_balance(delta): global account_balance with account_balance_lock: # Critical section is within this block. account_balance += delta |
假设
- 读取当前值
- 将 RHS 添加到该值
- 将累计值写回 LHS(技术上用 Python 术语绑定它)
如果您没有
1 2 3 | pos = threading.Thread(target=change_account_balance, args=[100]) neg = threading.Thread(target=change_account_balance, args=[-100]) pos.start(), neg.start() |
- pos: 读取当前值 -> 0
- neg: 读取当前值 -> 0
- pos:将当前值添加到读取值 -> 100
- neg:将当前值添加到读取值 -> -100
- pos: 写入当前值 -> account_balance = 100
- neg: 写入当前值 -> account_balance = -100
因为您没有强制操作在离散块中发生,所以您可以有三种可能的结果(-100、0、100)。
注意:此模式有一个警告:您必须记住每次要操作
编辑:回想起来,可能很重要的是要提到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import logging # This module is thread safe. import threading LOCK = threading.Lock() def run(): if LOCK.acquire(False): # Non-blocking -- return whether we got it logging.info('Got the lock!') LOCK.release() else: logging.info("Couldn't get the lock. Maybe next time") logging.basicConfig(level=logging.INFO) threads = [threading.Thread(target=run) for i in range(100)] for thread in threads: thread.start() |
我还想补充一点,锁的主要目的是保证获取的原子性(
代码的关键部分是一次只能由一个线程执行的代码。以聊天服务器为例。如果每个连接(即每个最终用户)都有一个线程,则一个"关键部分"是假脱机代码(向所有客户端发送传入消息)。如果有多个线程同时尝试对一条消息进行假脱机,您将得到 BfrIToS MANTWD PIoEmesCEsaSges 交织在一起,这显然一点都不好。
锁是可以用来同步访问关键部分(或一般资源)的东西。在我们的聊天服务器示例中,锁就像一个锁着的房间,里面有一台打字机。如果一个线程在那里(输入消息),则没有其他线程可以进入房间。一旦第一个线程完成,他解锁房间并离开。然后另一个线程可以进入房间(锁定它)。 "Aquiring" 锁只是意味着"我得到了房间。"
"临界区"是一段代码,为了正确起见,必须确保该部分中一次只能有一个控制线程。通常,您需要一个临界区来包含将值写入内存的引用,这些引用可以在多个并发进程之间共享。