这里有ManualResetEvent或ManualResetEventSlim的用法是什么?

时间:2018-05-19 09:05:53

标签: c# multithreading unit-testing asynchronous async-await

我有一个测试,我想确保我将从async方法获得每个线程的孤立结果。我的测试如下所示:

public async Task MyMethod_Concurrency_ReturnsIsolatedResultPerThread()
{
    int expectedResult = 20;

    var theMock = new Mock<IService>();
        theMock.Setup(m => m.GetResult(It.IsAny<int>()))
            .Callback(() => Thread.Sleep(10))
            .Returns<int>(t => Task.FromResult(expectedResult));

        var sut = new MyClass(30, theMock.Object);

        var rs1 = new ManualResetEventSlim();
        var rs2 = new ManualResetEventSlim();

        var task1 = Task.Run(async () =>
        {
            expectedResult = 40;
            await sut.MyMethod();
            rs2.Set();
            rs1.Wait();
            Assert.AreEqual(expectedResult, sut.Result);
        });

        var task2 = Task.Run(async () =>
        {
            rs2.Wait();
            expectedResult = 45;
            await sut.MyMethod();
            Assert.AreEqual(expectedResult, sut.Result);
            rs1.Set();
        });

        var task3 = Task.Run(() => Assert.AreEqual(0, sut.Amount));

        await Task.WhenAll(task1, task2, task3);
    }

测试工作正常并成功通过。但是,如果不使用ManualResetEventSlim,它也可以按预期工作。所以我的问题是这个例子中ManualResetEventSlim的用法是什么?我真的很困惑吗?任何人都可以解释在我的测试中使用ManualResetEventSlim或不使用它有什么区别?我该怎么做,以便我的测试不会在不使用ManualResetEvents ??

的情况下通过

1 个答案:

答案 0 :(得分:0)

Task.WhenAll()仅等待所有任务,直到运行完成。它会将结果排序以匹配任务对象的传递顺序,但它不会强制执行任何执行顺序,尽管所有任务始终以其发生的顺序在内部启动(请参阅source code)。如果您需要一个固定的执行订单,那么您必须自己处理,例如:使用WaitHandle,如ManualRestEvent或Semaphore或使用任务延续方法。

这意味着如果您的任务都在同一时间内运行(如您的示例中),则它们以相同的顺序启动并以相同的顺序完成。 但是,如果您的任务在不同时间执行,例如task1 - &gt; 2000毫秒和任务2 - &gt; 20 ms,比task2在task1之前很久就完成了。

或者当task1花费比task2更长的时间来访问 sut.MyMethod()的调用时,使用你的例子,结果不会相同。现在,如果您需要在task2之前完成task1,则需要控制流程。