ManualResetEventSlim.Set()并不总是解锁在任务中等待

时间:2022-06-01 19:41:06

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.

并且在任务内部等待之后的代码永远不会被调用。

I'm using .NET Core 2.0.2 on Windows Server 2012 R2 with Visual Studio 15.4.1.

我在Windows Server 2012 R2和Visual Studio 15.4.1上使用.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.

当我在Debug / Release配置中在命令行中构建和运行代码时,似乎没有问题。

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. I'm suspecting a minor bug in the IDE. However I can't report it because it has disappeared now.

结果:在重新启动IDE,清理项目和重新完成项目之后,到目前为止我还没有遇到过这个问题。我怀疑IDE中的一个小错误。但是我无法报告,因为它现在已经消失了。

I'm leaving this question open in case someone else encounters this issue and would want to track and report the bug.

我打开这个问题,以防其他人遇到这个问题,并希望跟踪并报告错误。

1 个解决方案

#1


0  

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.0111623. I also read that

我从主线程获得消息Hello! 00:00:01.0111623。我也看了

A single call to Set() signals the event, and any waiting Tasks are released. New calls to Wait() don't block until Reset() method called.

对Set()的单次调用会向事件发出信号,并释放所有等待的任务。在调用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.

你会发现一切都按预期工作。

#1


0  

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.0111623. I also read that

我从主线程获得消息Hello! 00:00:01.0111623。我也看了

A single call to Set() signals the event, and any waiting Tasks are released. New calls to Wait() don't block until Reset() method called.

对Set()的单次调用会向事件发出信号,并释放所有等待的任务。在调用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.

你会发现一切都按预期工作。