在Python中,双重检查锁定是否线程安全?

16

双重检查锁定模式在某些语言中不可靠,我想知道Python是否属于这类语言。更具体地说,以下代码是否可行...

# Objects shared by threads:
obj = None
lock_for_obj = threading.Lock()

def get_obj():
    """Function called concurrently by threads."""
    if obj is None:
        with lock_for_obj:
            if obj is None:
                obj = factory()  # Never returns `None`
    return obj

Python 中的线程安全吗?是否有场景或实现是线程安全的或不安全的?为什么?


你假设在另一个线程正在修改缓存时,对缓存执行查找是安全的。即使有GIL(并非所有Python实现都有GIL),这也不完全安全。 - user2357112
@user2357112: 什么缓存?处理器缓存?我愿意相信没有GIL的实现可能有不同的安全规则,但是如果GIL没有提供缓存一致性,在CPython中不会所有东西都出问题吗? - Davis Herring
@DavisHerring 啊,他们是在回答我之前编辑掉的问题的旧版本。 - Brian Rodriguez
@BrianRodriguez:嗯。你的问题的原始版本对于CPython来说有一个非常有趣的答案,至少在factory的调用没有副作用(在创建的对象之外)的情况下。 - Davis Herring
obj is None 是对 obj 的读取,而 return obj 则是另一个读取操作,因此存在一种可能的代码路径,即在没有任何同步操作的情况下进行两次 obj 的读取。即使在双重检查锁定有效的语言中也可能会出现这种情况;通常需要将 obj 读入本地变量以用于测试和返回,以便没有同步操作的代码路径只承载一个读取操作。 - Holger
显示剩余2条评论
1个回答

2
请看PEP 583 - Python并发内存模型,但该提案已被撤回。
我猜它被撤回的原因是(虽然我找不到足够的信息)因为Python有不同的实现,很难在每个实现上强制执行这样的标准。
结论:当使用单处理器的CPython实现时,这段代码可能是安全的,或者使用Jython实现时通常也可能是安全的,但不能保证。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接