2016-09-30 57 views
3

我需要檢查一個Parallel.ForEach的任何迭代是否達到特定點。從我的理解下面將是安全的,如果我的boolvolatile領域,但它需要在外層方法的變量:從C#中的多個線程安全地寫入一個bool變量?

bool anySuccess = false; 
Parallel.ForEach(things, thing => 
{ 
    // stuff happens... 
    anySuccess = true; 
}); 
if(!anySuccess) 
    throw new Exception("No things succeeded :("); 

我可以使用此代碼按原樣或我應該使用lockInterlocked功能?

+0

如果爲'anySuccess只寫'是將它設置爲真,並且直到處理完成之後纔會讀取它,那麼你可能會逃避它。但我會建議使用鎖。 – stuartd

+3

您也可以最後使用Volatile.Read(!anySuccess)檢查。 – Evk

+0

在這種特定情況下,AnySuccess上可能發生的唯一操作是將其設置爲true。這意味着不同線程之間不會有任何競爭條件,例如一個線程將anySuccess設置爲false,另一個線程同時將其設置爲true。所以在這裏你甚至不需要鎖定或並行的foreach;即使你在同一時刻開啓所有線程,也沒有什麼不好的事情發生。 – Nebr

回答

3

如果該代碼是循環訪問該布爾值的ENTIRETY,那麼對我而言似乎是安全的。

一般來說基本值類型不是線程安全的,因爲對它們執行的許多操作都不是原子的。

但是,如果你曾經做的是分配給該變量ONLY的事情...從來沒有閱讀它的基礎上,它永遠不會改變分支的基礎上,它從來沒有寫入它的當前狀態......和所有的寫是相同的(可能發生的唯一修改是將其設置爲true),那麼我看不出有任何方式導致非原子性問題。

== ADDITION ==

在當前代碼的正確性上述評論。代碼在其上下文中作爲代碼庫的一部分的長期安全性也值得考慮。讓代碼保持原樣,爲未來的開發人員設置一個陷阱,這個開發人員不知道/理解/識別正在發生的事情,以及爲什麼它當前是安全的。

如果你這樣說,就必須對聲明和單一用法做一個CLEAR評論,解釋發生了什麼,爲什麼它是安全的,以及爲什麼他們不開始閱讀/使用變量其他方法。

替代方案(添加鎖定代碼)是長期安全的,但性能可能稍低一些。

+0

如果線程讀取anySuccess不會看到它被改變,因爲它會讀取緩存在CPU寄存器中的值(false)?你不需要Volatile.Read那裏? – Evk

+0

@Evk沒有東西在讀它......這是我答案的全部內容。 – Brondahl

+0

那是怎麼回事?如果(!anySuccess)阻止? – Evk

-1

我會鎖定布爾。另外,我建議將if語句移動到Parallel.Foreach塊中。原因:

這將並行循環後評估,因此只讀取的anySuccess

bool anySuccess = false; 
Parallel.ForEach(things, thing => 
{ 
    // stuff happens... 
    anySuccess = true; 
}); 
if(!anySuccess) 
    throw new Exception("No things succeeded :("); 

這最後一次更新將評估布爾的所有更新

Object myLock = new Object(); 

bool anySuccess = false; 
Parallel.ForEach(things, thing => 
{ 
    // stuff happens... 
    lock (myLock) 
    { 
     anySuccess = true; 
    } 
    if(!anySuccess) 
     throw new Exception("No things succeeded :("); 
}); 
+0

這是功能的改變。鑑於anySuccess沒有被設置爲true的第一個「東西」達到這一點,這將立即終止,即使並非所有的東西都已經被處理。使用原始代碼,確保所有事情都得到正確處理。 – Nebr

相關問題