lock vs boolean

时间:2012-06-19 11:19:05

标签: c# multithreading locking

这里的情景:

计时器每分钟调用一个方法。可以通过UI(按钮)调用此方法。我希望如果我的方法是“进行中”,并且被调用,它不会执行该方法两次。

在我的方法中,我使用一个简单的布尔值:

    private bool _isProcessing;
    public void JustDoIt(Action a, int interval, int times)
    {
        if (!_isProcessing)
        {
            _isProcessing = true;
            for (int i = 0; i < times; i++)
            {
                a();
                Thread.Sleep(interval);
            }
        }
        _isProcessing = false;
    }

工作正常。我用这个测试来测试这个功能:

    [Test]
    public void Should_Output_A_String_Only_3_Times()
    {
        var consoleMock = new Mock<IConsole>();
        IConsole console = consoleMock.Object;
        var doer = new Doer { Console = console };

        Action a = new Action(() => console.Writeline("TASK DONE !"));

        // Simulate a call by Timer
        var taskA = Task.Factory.StartNew(() => doer.JustDoIt(a, 1000, 3));

        // Simulate a call by UI
        var taskB = Task.Factory.StartNew(() => doer.JustDoIt(a));

        taskA.Wait();
        consoleMock.Verify(c => c.Writeline("TASK DONE !"), Times.Exactly(3));
    }

开发人员检查我的代码并说:“我用lock关键字替换了你的布尔值。它更多是线程安全。坦率地说,我没有掌握多线程,所以我回答他”好的盖伊!“

几天后(今天更精确),我想测试一下如果使用lock或一个简单的布尔值之间的区别。所以当我用lock关键字替换布尔值时,我很惊讶于这样:

    private object _locker = new Object();
    public void JustDoIt(Action a, int interval, int times)
    {
        lock (_locker)
        {
            //_isProcessing = true;
            for (int i = 0; i < times; i++)
            {
                a();
                Thread.Sleep(interval);
            }
        }
        //_isProcessing = false;
    }

先例测试未通过:

  

消息:Moq.MockException:对模拟的预期调用恰好是3次,但是是4次:c =&gt; c.Writeline(“TASK DONE!”)

那么,我是否严重使用lock关键字?应该是'静态'吗?

谢谢

2 个答案:

答案 0 :(得分:2)

_isProcessing变得不稳定。然后这样做:

public void JustDoIt(Action a, int interval, int times)
{
    if (_isProcessing) return
    _isProcessing = true;
    for (int i = 0; i < times; i++)
    {
        a();
        Thread.Sleep(interval);
    }
    _isProcessing = false;
}

这有一个小的竞争条件,但由于你的代码无论如何都没有与任何东西同步,我不相信它可能很重要。

答案 1 :(得分:0)

你只需要锁定它,这意味着其他想要进入关键部分的线程等待锁定,如果当前线程/任务释放它们,它们将进入锁定状态。

例如:TaskA获取锁,它现在处于Critical Section并执行方法a()3次。当TaskA完成执行时,它会释放锁定并且可能存在上下文切换,因此TaskB运行方法a()(第4次)。 在TaskB返回之后,主线程说...“嘿,TaskA已经完成,所以我验证了我的结果”

添加到那个,我不知道TaskA是否必须在TaskB之前运行。所以,我不知道Task-Scheduler是否是FIFO。