讓我們假設有一個靜態變量被2個線程訪問。解決C#中的線程衝突
public static int val = 1;
現在假設線程1執行是這樣的
if(val==1)
{
val +=1
}
檢查後加在上述聲明線程2之前但是
聲明val的值更改爲別的東西。
現在,這會造成一些討厭的錯誤。這發生在我的代碼中。
有沒有什麼辦法讓線程1注意到val的值已被更改,而不是添加回去並再次執行檢查。
讓我們假設有一個靜態變量被2個線程訪問。解決C#中的線程衝突
public static int val = 1;
現在假設線程1執行是這樣的
if(val==1)
{
val +=1
}
檢查後加在上述聲明線程2之前但是
聲明val的值更改爲別的東西。
現在,這會造成一些討厭的錯誤。這發生在我的代碼中。
有沒有什麼辦法讓線程1注意到val的值已被更改,而不是添加回去並再次執行檢查。
您可以在訪問val或更新val時使用鎖。見http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx
你可以使用鎖:
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`
}
看起來好像不是一個好主意,可以檢查鎖外val的值,然後在鎖內重新執行它。如果您將每個對val的訪問放入鎖中,無論它是讀取還是寫入,都無需擔心有人在觸摸它之前搞亂了它。因此,你得到了鎖,然後檢查val,並且可以確保沒有其他人在你做之前觸摸val。 –
@MichaelMankus - 在你的情況下,無論你是否需要鎖,你都會鎖定。檢查一個值通常是廉價的,而獲得一個鎖是更昂貴的,並且可以阻止其他代碼等待鎖。請查看http://en.wikipedia.org/wiki/Double-checked_locking –
的推理。我從來沒有仔細檢查過我的鎖。看起來這是我會開始做的事情。 –
專門爲你的榜樣,你可以:
var originalValue = Interlocked.CompareExchange(ref val,
2, //update val to this value
1); //if val matches this value
if(originalValue == 1)
{
//the update occurred
}
以及我的例子只是我在代碼中遇到的問題的簡化版本。我不認爲上述方法在我的真實代碼中很容易使用。 –
@WinCoder:看看Interlocked提供的內容,因爲它可能仍然有適合您需要的工具。 – spender
如果你想增加一個線程安全的方式整數值,您可以使用靜態Interlocked.Increment
方法:Interlocked.Increment Method (Int32)
基礎的在你的問題上,我建議'Interlocked.CompareExchange',如下面答案中的建議。如果你認爲這不合適,你應該改變你的問題,向我們展示你正試圖解決的*真實*問題。 –