简体   繁体   中英

What is the usage of ManualResetEvent or ManualResetEventSlim here?

I have a test and I want to make sure that I will get isolated result per Thread from an async method. My test is look like the following:

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

The test works fine and passed successfully. However without using ManualResetEventSlim it also works as expected. So my question is what is the usage of ManualResetEventSlim in this example? I'm really confused with that? Can anybody please explain what is difference between using ManualResetEventSlim or not using it in my test? What can I do, so that my test won't be passed without using ManualResetEvents ??

Task.WhenAll() does only wait for all tasks until run to completion. It will order the results to match the order the task objects were passed, but it does not enforce any order of execution although all Tasks are always internally started in their occurring order (see source code ). If you need a fixed execution order than you must take care of it yourself eg by using a WaitHandle like ManualRestEvent or a Semaphore or using the task continuation methods.

This means if your tasks are all equally short running (like in your example) than they are started in the same order and complete in the same order. But if your tasks execute in different times, eg task1 -> 2000 ms and task2 -> 20 ms, than task2 would complete long before task1.

Or to use your example when task1 takes longer than task2 to reach the invocation of sut.MyMethod() the result won't be the same. Now if you need task1 to complete before task2 you need to control the flow.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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