简体   繁体   English

ManualResetEventSlim.Set() 并不总是解锁任务内的等待

[英]ManualResetEventSlim.Set() does not always unlock the Wait inside a Task

I am trying to use the ManualResetEventSlim class to communicate between a few parallel Tasks.我正在尝试使用ManualResetEventSlim类在几个并行任务之间进行通信。

Here is a simplified version of the code:这是代码的简化版本:

class Program
{
    private static void Main(string[] args)
    {
        Stopwatch stopwatch = Stopwatch.StartNew();

        ManualResetEventSlim eventSlim = new ManualResetEventSlim(false);

        Task.Run(() =>
        {
            Task.Run(() =>
                            {
                                Thread.Sleep(1000);

                                eventSlim.Set();
                            });

            eventSlim.Wait();

            Console.WriteLine($"Hello from the Task! {stopwatch.Elapsed}");
        });

        eventSlim.Wait();

        Console.WriteLine($"Hello from the Main thread! {stopwatch.Elapsed}");

        stopwatch.Stop();

        Console.ReadLine();
    }
}

Most of the times the code runs fine and outputs:大多数情况下,代码运行良好并输出:

Hello from main thread! 00:00:01.1017591
Hello from task! 00:00:01.1017630

However once in every five or six times I run the code I only get this output:但是,每五六次运行一次代码,我只会得到以下输出:

Hello from main thread! 00:00:01.1017591

And the code after the Wait inside the Task never gets called.而 Task 中Wait之后的代码永远不会被调用。

I'm using .NET Core 2.0.2 on Windows Server 2012 R2 with Visual Studio 15.4.1 .我在带有Visual Studio 15.4.1 Windows Server 2012 R2上使用.NET Core 2.0.2

Can anyone reproduce this behaviour?任何人都可以重现这种行为吗?

Can anyone confirm if my code is right or if there is any problems with it please?任何人都可以确认我的代码是否正确或者它是否有任何问题?

Update After @ArhiChief suggested to test the results in the Release configuration, I figured that the problem only appears when I am using the IDE to debug my code.更新@ArhiChief 建议在 Release 配置中测试结果后,我发现问题仅在我使用 IDE 调试代码时出现。

When I build and run the code in the command line in either Debug/Release configuration, there seem to be no problems.当我在调试/发布配置中的命令行中构建和运行代码时,似乎没有问题。

I tried to close/reopen the IDE and clean the project and do a fresh rebuild, and now the IDE seems to be working fine too.我尝试关闭/重新打开 IDE 并清理项目并重新构建,现在 IDE 似乎也工作正常。

Results: I haven't faced the issue so far after restarting the IDE, cleaning the project and doing a fresh rebuild of the project.结果:在重新启动 IDE、清理项目并重新构建项目后,到目前为止我还没有遇到过这个问题。 I'm suspecting a minor bug in the IDE.我怀疑 IDE 中存在小错误。 However I can't report it because it has disappeared now.但是我不能报告它,因为它现在已经消失了。

I'm leaving this question open in case someone else encounters this issue and would want to track and report the bug.如果其他人遇到此问题并希望跟踪和报告错误,我将保留此问题。

I'm also have an idea what your first task may be disposed and collected.我也知道你的第一个任务可能会被处理和收集。 Consider this code考虑这个代码

static void Main(string[] args)
{
Stopwatch stopwatch = Stopwatch.StartNew();

ManualResetEventSlim eventSlim = new ManualResetEventSlim(false);

Task.Run(() =>
{
    Task.Run(() =>
    {
        Thread.Sleep(1000);

        eventSlim.Set();
    });

    eventSlim.Wait();

    Console.WriteLine($"Hello from the Task! {stopwatch.Elapsed}");
});

eventSlim.Wait();

Console.WriteLine($"Hello from the Main thread! {stopwatch.Elapsed}");

stopwatch.Stop();

//Console.ReadLine();
}

I get message Hello from the Main thread! 00:00:01.0111623Hello from the Main thread! 00:00:01.0111623收到消息Hello from the Main thread! 00:00:01.0111623 Hello from the Main thread! 00:00:01.0111623 . Hello from the Main thread! 00:00:01.0111623 I also read that我也读过

A single call to Set() signals the event, and any waiting Tasks are released.对 Set() 的单个调用发出事件信号,并释放任何等待的任务。 New calls to Wait() don't block until Reset() method called.在调用 Reset() 方法之前,对 Wait() 的新调用不会阻塞。

But lets return to our code.但是让我们回到我们的代码。 If you rewrite it like this如果你像这样重写它

static void Main(string[] args)
{
Stopwatch stopwatch = Stopwatch.StartNew();

ManualResetEventSlim eventSlim = new ManualResetEventSlim(false);

var t = Task.Run(() =>
{
    Task.Run(() =>
    {
        Thread.Sleep(1000);

        eventSlim.Set();
    });

    eventSlim.Wait();

    Console.WriteLine($"Hello from the Task! {stopwatch.Elapsed}");
});

eventSlim.Wait();

Console.WriteLine($"Hello from the Main thread! {stopwatch.Elapsed}");

stopwatch.Stop();

t.Wait();
//Console.ReadLine();
}

you will find that everything works as you expected.你会发现一切都如你所愿。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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