在简单地分配变量时,我需要使用锁吗

本文关键字:简单 分配 变量 | 更新日期: 2023-09-27 18:20:50

当多线程时,我知道如果要向列表中添加和项等操作,我需要锁定变量,否则会出现跨线程异常。但是,在分配变量时,我需要锁定它们吗?我不介意线程是否获得该变量的旧实例——我只是不希望它出错。下面是我的意思的一个例子:

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

运行代码应该会给出答案。。。将结果写入屏幕并运行,而不是while(true)写入for(i=1;1<1e6;i++)

你会看到它加起来不是2e6,而是大约1.2e6。所以,是的,如果你想出去,你需要上锁。

不要只是假设,之后总是测试和断言。

您必须记住,线程也可能正在查看过时的副本,通过锁定确保您正在查看的变量的版本正在刷新

当我刚开始编码时,我认为也许我不需要变量的最新副本,我会陷入无限循环,因为我认为变量最终会更新,但如果变量被缓存,它就永远不会更新

我包括了一些带有简短描述的例子,不用担心线程的启动方式,这与无关

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

当您启动循环时,有可能会继续获得变量的陈旧副本,这就是为什么您在访问跨多个线程的时需要某种同步的原因