我最近编写了一个使用简单生产者/消费者模式的程序。它最初有一个与不正确使用 threading.Lock 相关的错误,我最终修复了该错误。但这让我思考是否有可能以无锁的方式实现生产者/消费者模式。
我的要求很简单:
- 一个生产者线程。
- 一个消费者线程。
- 队列只能放置一项。
- 生产者可以在当前项目被消耗之前生产下一个项目。因此,当前项目丢失了,但这对我来说没关系。
- 消费者可以在生产下一个项目之前消费当前项目。因此,当前项目被消耗了两次(或更多),但这对我来说没关系。
所以我写了这个:
QUEUE_ITEM = None
# this is executed in one threading.Thread object
def producer():
global QUEUE_ITEM
while True:
i = produce_item()
QUEUE_ITEM = i
# this is executed in another threading.Thread object
def consumer():
global QUEUE_ITEM
while True:
i = QUEUE_ITEM
consume_item(i)
我的问题是:这段代码是线程安全的吗?
立即评论:这段代码并不是真正无锁的——我使用 CPython,它有 GIL。
我对代码进行了一些测试,它似乎可以工作。它转换为一些由于 GIL 而具有原子性的 LOAD 和 STORE 操作。但我也知道当 x 实现方法del x
时操作不是原子的。__del__
因此,如果我的项目有一个__del__
方法并且发生了一些令人讨厌的调度,事情可能会中断。或不?
另一个问题是:我必须施加什么样的限制(例如对生产项目的类型)才能使上述代码正常工作?
我的问题只是关于利用 CPython 和 GIL 的怪癖以提出无锁(即没有像 threading.Lock 这样的锁在代码中显式)解决方案的理论可能性。