0

有人可以告诉我以下是否是线程安全的,如果不是,我必须做什么才能做到这一点。

注意:这只是一个小样本,不确定它是否运行。

TIMER = True
time_lock = threading.Lock()
def timing():
    while TIMER:
        # some logic will be here for now print time
        print time.time()

timer = threading.Thread(target=timing)
timer2 = threading.Thread(target=timing)
timer.start()
timer2.start()

while True:
    time_lock.aquire()
    if doSomeStuff():
        TIMER = True
    if otherThings():
        break
    time_lock.aquire()
    TIMER = False
    time_lock.release()

time_lock.aquire()
TIMER = False
time_lock.release()
4

2 回答 2

2

这在一定程度上取决于您使用的是哪种实现,以及您在做什么。

首先,在 python 的事实上的标准实现(“cpython”)中,一次只允许运行一个线程,因为 python 解释器的某些内部结构不是线程安全的。这是由全局解释器锁(又名“GIL”)控制的。所以在 cpython 中,你根本不需要额外的锁;GIL 确保一次只有一个线程在运行 python 代码并可能更改变量。这是实现的一个特性,而不是语言的特性。

其次,如果只有一个线程写入一个简单的变量而其他线程只读取它,那么出于显而易见的原因,您也不需要锁。但是,作为程序员,您可以确保情况确实如此,并且很容易出错。

即使分配给一个简单的变量也可能不需要锁。在 python 中,变量更像是用于引用对象的标签,而不是可以放入某些内容的框。所以简单的赋值是原子的(从某种意义上说,它们不能被中途中断),当您查看生成的python字节码:

In [1]: import dis

In [2]: x = 7

In [3]: def setx():
    global x
    x = 12
   ...:     

In [4]: dis.dis(setx)
  3           0 LOAD_CONST               1 (12)
              3 STORE_GLOBAL             0 (x)
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE        

唯一改变 x 的代码是单个STORE_GLOBAL操作码。所以变量要么改变,要么不改变;之间没有不一致的状态。

但是,如果您想测试某个变量的某个值,并在该测试仍然成立时执行一项操作,您确实需要一个锁。因为另一个线程可能在您测试后更改了变量。

诸如附加到列表或交换变量之类的事情不是原子的。但同样在 cpython 中,这些将受到 GIL 的保护。在其他实现中,您需要锁定此类操作以防止可能的不一致。

于 2012-10-24T18:08:41.307 回答
1

如果我对您的理解正确,您想在停止时向您的线程发出信号。由于这是一种只有一个线程写入共享变量且仅一次的情况,因此您不需要锁。

当您对无法以原子方式读取的共享数据结构进行并发修改时,锁是必需的。

于 2012-10-24T13:23:24.450 回答