簡體   English   中英

簡單分配變量時是否需要使用鎖?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM