[英]Do I need to use locks when simply assigning variables?
當執行多線程時,我知道如果要執行諸如在列表中添加和添加項等操作,則需要鎖定變量,否則我將獲得跨線程異常。 但是,僅在分配變量時需要鎖定它們嗎? 我不介意線程是否獲取變量的舊實例-我只是不希望它出錯。 這是我的意思的示例:
public void Run()
{
var thread1 = new Thread(new ThreadStart(Test));
var thread2 = new Thread(new ThreadStart(Test));
thread1.Start();
thread2.Start();
}
private static int _test;
private void Test()
{
while (true)
{
_test += 1;
}
}
如果您只是分配一個int
,則不會。 但是在這里,您不僅僅是分配。 您正在增加。 因此,您需要某種同步。
如果要增加,請使用Interlocked.Increment :
Interlocked.Increment(ref _test);
您必須記住,線程也可能正在查看過時的副本,方法是鎖定以確保您正在查看的變量的版本已刷新
當我剛開始編碼並認為也許不需要最新的變量副本時,我會陷入無限循環,因為我認為變量最終會被更新,但是如果該變量被緩存,則它將永遠不會更新
我提供了帶有簡短說明的示例,不用擔心線程啟動的方式,這無關緊要
private static bool _continueLoop = true;
private static readonly object _continueLoopLock = new object();
private static void StopLoop()
{
lock(_continueLoopLock)
_continueLoop = false;
}
private static void ThreadALoopWillGetStales()
{
while(_continueLoop)
{
//do stuff
//this is not guaranteed to end
}
}
private static void ThreadALoopEventuallyCorrect()
{
while(true)
{
bool doContinue;
lock(_continueLoopLock)
doContinue = _continueLoop;
if(!doContinue)
break;
//do stuff
//this will sometimes result in a stale value
//but will eventually be correct
}
}
private static void ThreadALoopAlwaysCorrect()
{
while(true)
{
bool doContinue;
lock(_continueLoopLock)
if(!_continueLoop)
break;
//do stuff
//this will always be correct
}
}
private static void ThreadALoopPossibleDeadlocked()
{
lock(_continueLoopLock)
while(_continueLoop)
{
//if you only modify "_continueLoop"
//after Acquiring "_continueLoopLock"
//this will cause a deadlock
}
}
private static void StartThreadALoop()
{
ThreadPool.QueueUserWorkItem ((o)=>{ThreadALoopWillGetStales();});
}
private static void StartEndTheLoop()
{
ThreadPool.QueueUserWorkItem((o)=>
{
//do stuff
StopLoop();
});
}
public static void Main(string[] args)
{
StartThreadALoop();
StartEndTheLoop();
}
當您開始循環時,有機會繼續獲取該變量的陳舊副本,這就是為什么在訪問多個線程時確實需要某種同步的原因
運行代碼應該給您答案...而不是while(true)
編寫for(i=1;1<1e6;i++)
,將結果寫入屏幕並運行。
您會發現它的總和不是2e6,而是大約1.2e6。 所以是的,如果您想退出2e6,則需要鎖定。
不要只是假設,在此之后始終進行測試和斷言。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.