Python: 'not in' 期间列表更改大小会导致 UB 吗?

Python: Will A List Changing Size During 'not in' Cause UB?

我有一个有两个线程的假设程序。

items = [ 'A', 'B' ]


func1():
    while True:
        if 'C' not in items:
            # do something
        
func2():
    while True:
        items.clear()
        items.append('A')
        items.append('B')

main():
    start_new_thread(func1)
    start_new_thread(func2)

当执行 not in 时,我假设 Python 必须在内部迭代列表以检查每个元素。如果func2在迭代过程中改变了这个列表的大小,会不会导致异常或者UB?

永远不要允许两个线程在任何编程语言中同时访问同一块内存。这将创建一个 data race condition which leads to extremely undefined behavior (If your programming language of choice cannot detect this and throw an exception). The safest thing to do is use a lock 对象,如果另一个线程已获取锁,则强制停止执行一个线程,并等待直到可以安全地再次修改数据。这是添加了锁的最小示例(并且还修改为实际工作代码)。

import threading

items = [ 'A', 'B' ]
lock = threading.Lock()

def func1():
    while True:
        lock.acquire()
        if 'C' not in items:
            print("C not in items")
        lock.release()

def func2():
    while True:
        lock.acquire()
        items.clear()
        items.append('A')
        items.append('B')
        lock.release()

def main():
    thread_a = threading.Thread(target=func1, daemon=True)
    thread_b = threading.Thread(target=func2, daemon=True)
    thread_a.start()
    thread_b.start()
    thread_a.join()
    thread_b.join()

main()

请注意,许多库可能将它们的某些函数称为“线程安全”。这意味着他们已经处理了任何潜在的数据竞争条件,您不必担心设置锁。您可能还会遇到“原子”操作,这基本上只是意味着它们是线程安全的操作。不过,原子操作在 python 中并不是真正的东西。