2016-10-18 95 views
2

以下代碼是否線程安全?
只有一個/第一個線程設置變量,set_this_var_only_once?Python:多線程設置變量一次

set_this_var_only_once = None 

def worker(): 
    global set_this_var_only_once 
    if set_this_var_only_once is None: 
     set_this_var_only_once = "not None" 

for i in range(10): 
    t = threading.Thread(target=worker) 
    t.daemon=True 
    t.start() 
+2

如果兩個或更多的工人檢查條件之前任何一方的設置變量? –

+0

@machineyearning這是我的擔心 – ealeon

回答

3

絕對不是。

這很可能是兩個線程執行下一個前執行這一行:

if set_this_var_only_once is None: 

之後,兩個線程將執行下一行:

 set_this_var_only_once = "not None" 

您可以使用locks來防止:

lock = threading.Lock() 

def worker(): 
    lock.acquire() 
    if set_this_var_only_once is None: 
     set_this_var_only_once = "not None" 
    lock.release() 

只有一個線程將能夠到獲得的鎖定。如果另一個線程在鎖定時嘗試獲取它,對lock.acquire()的調用將會阻塞並等待,直到鎖定爲由第一個線程釋放。然後該鎖將由另一個線程獲取。

這樣可以確保lock.acquire()lock.release()之間的代碼一次在一個線程中執行。

編輯

如格哈德在the other answer指出,可以用鎖使用context management protocol

with lock: 
    if set_this_var_only_once is None: 
     set_this_var_only_once = "not None" 

這也將確保鎖在一個異常的情況下,正確地釋放內鎖定塊。

1

不,它不是。

如果另一個線程獲取當前線程控制後已取出 的變量,它可以獲取變量,增加它,並把它寫回 ,當前線程做同樣的事情之前。並且由於它們是 都看到相同的原始值,因此只有一個項目將被計入 。

Here's這篇關於它的好文章。

P.S.還需要在工人()以下行:

global set_this_var_only_once 
4

你需要鎖定這樣的變量:

from threading import Lock 

lock = Lock() 
set_this_var_only_once = None 

def worker(): 
    with lock: 
     if set_this_var_only_once is None: 
      set_this_var_only_once = "not None 
+1

使用'with'是一個很好的觸摸;) – zvone

+0

使代碼更清晰,並且與Java的同步塊幾乎相同,即synchronized(鎖定){/ * code * /}。 –