3

ここでシナリオ:

メソッドは、タイマーによって毎分呼び出されます。このメソッドは、UI (ボタン) から呼び出すことができます。メソッドが「処理中」で呼び出された場合、メソッドが 2 回実行されないようにしたいと考えています。

私の方法では、単純なブール値を使用します:

    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 キーワードに置き換えると、constate に驚きました。

    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=>c.Writeline("TASK DONE !")

では、lock キーワードの使い方が悪いのでしょうか? 「静的」にする必要がありますか?

ありがとうございました

4

2 に答える 2

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

これにはマイナーな競合状態がありますが、とにかくコードが何にも同期されていないため、問題になる可能性はないと思います.

于 2012-06-19T11:33:49.410 に答える
0

あなたはそれをロックするだけです。つまり、クリティカルセクションに入りたい他のスレッドはロックを待ち、現在のスレッド/タスクがそれを解放すると彼らはロックに入ります。

例:TaskAはロックを取得し、クリティカルセクションにあり、メソッドa()を3回実行します。TaskAが実行を終了すると、ロックが解除され、コンテキストスイッチが存在する可能性があるため、TaskBはメソッドa()を実行します(4回目)。TaskBがメインスレッドを返した後、「ねえ、TaskAは終了したので、結果を確認します」と言います。

それに加えて、TaskAがTaskBの前に実行する必要があるかどうかはわかりません。したがって、タスクスケジューラがFIFOであるかどうかはわかりません。

于 2012-06-19T11:37:13.507 に答える