简体   繁体   English

简单分配变量时是否需要使用锁?

[英]Do I need to use locks when simply assigning variables?

When multithreading I know that I need to lock variables if doing things like adding and item to a list etc or I would get a cross thread exception. 当执行多线程时,我知道如果要执行诸如在列表中添加和添加项等操作,则需要锁定变量,否则我将获得跨线程异常。 But do I need to lock them when just assigning variables? 但是,仅在分配变量时需要锁定它们吗? I don't mind about if a thread getting an old instance of the variable - I just don't want it to error. 我不介意线程是否获取变量的旧实例-我只是不希望它出错。 Here is an example of what I mean: 这是我的意思的示例:

    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;
        }
    }

If you're just assigning an int , then no. 如果您只是分配一个int ,则不会。 But here you're not just assigning. 但是在这里,您不仅仅是分配。 You're incrementing. 您正在增加。 So you need some kind of synchronization. 因此,您需要某种同步。

In you want to increment, use Interlocked.Increment : 如果要增加,请使用Interlocked.Increment

Interlocked.Increment(ref _test);

You have to remember the thread could also be looking at a stale copy, by locking you assure that the version of the variable you are looking at is being refreshed 您必须记住,线程也可能正在查看过时的副本,方法是锁定以确保您正在查看的变量的版本已刷新

When I first started coding and thought that maybe I don't need the freshest copy of the variable I would get stuck in infinite loops because I assume the variable would be updated eventually, but if the variable was cached then it would never update 当我刚开始编码并认为也许不需要最新的变量副本时,我会陷入无限循环,因为我认为变量最终会被更新,但是如果该变量被缓存,则它将永远不会更新

I included examples with brief descriptions, don't worry about the way the thread is started, that is not relevant 我提供了带有简短说明的示例,不用担心线程启动的方式,这无关紧要

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();
}

when you start the loop there is a chance that you will continue to get a stale copy of the variable, that is why you do need some sort of synchronization when accessing a across multiple threads 当您开始循环时,有机会继续获取该变量的陈旧副本,这就是为什么在访问多个线程时确实需要某种同步的原因

Running the code should give you your answer... instead of while(true) write for(i=1;1<1e6;i++) , write the result to screen and run it. 运行代码应该给您答案...而不是while(true)编写for(i=1;1<1e6;i++) ,将结果写入屏幕并运行。

You'll see it does not add up to 2e6, but rather something around 1.2e6. 您会发现它的总和不是2e6,而是大约1.2e6。 So yes, you need to lock if you want to get out 2e6. 所以是的,如果您想退出2e6,则需要锁定。

Don't just hypothesize, after that always test and assert. 不要只是假设,在此之后始终进行测试和断言。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM