2013-05-21 74 views
1

讓我們假設有一個靜態變量被2個線程訪問。解決C#中的線程衝突

public static int val = 1; 

現在假設線程1執行是這樣的

if(val==1) 
{ 
    val +=1 
} 
檢查後加在上述聲明線程2之前但是

聲明val的值更改爲別的東西。

現在,這會造成一些討厭的錯誤。這發生在我的代碼中。

有沒有什麼辦法讓線程1注意到val的值已被更改,而不是添加回去並再次執行檢查。

+3

基礎的在你的問題上,我建議'Interlocked.CompareExchange',如下面答案中的建議。如果你認爲這不合適,你應該改變你的問題,向我們展示你正試圖解決的*真實*問題。 –

回答

3

你可以使用鎖:

var lockObj = new object(); 

if(val == 1) // is the value what we want 
{ 
    lock(lockObj) // let's lock it 
    { 
     if(val == 1) // now that it's lock, check again just to be sure 
     { 
      val += 1; 
     } 
    } 
} 

如果走這樣一條路,你必須確保修改val任何代碼也使用與同一鎖定對象的鎖。

lock(lockObj) 
{ 
    // code that changes `val` 
} 
+0

看起來好像不是一個好主意,可以檢查鎖外val的值,然後在鎖內重新執行它。如果您將每個對val的訪問放入鎖中,無論它是讀取還是寫入,都無需擔心有人在觸摸它之前搞亂了它。因此,你得到了鎖,然後檢查val,並且可以確保沒有其他人在你做之前觸摸val。 –

+0

@MichaelMankus - 在你的情況下,無論你是否需要鎖,你都會鎖定。檢查一個值通常是廉價的,而獲得一個鎖是更昂貴的,並且可以阻止其他代碼等待鎖。請查看http://en.wikipedia.org/wiki/Double-checked_locking –

+0

的推理。我從來沒有仔細檢查過我的鎖。看起來這是我會開始做的事情。 –

6

專門爲你的榜樣,你可以:

var originalValue = Interlocked.CompareExchange(ref val, 
            2,  //update val to this value 
            1);  //if val matches this value 
if(originalValue == 1) 
{ 
    //the update occurred 
} 
+0

以及我的例子只是我在代碼中遇到的問題的簡化版本。我不認爲上述方法在我的真實代碼中很容易使用。 –

+0

@WinCoder:看看Interlocked提供的內容,因爲它可能仍然有適合您需要的工具。 – spender