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



我正在尝试使用ManualResetEventSlim类在几个并行任务之间进行通信。

以下是代码的简化版本:

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

大多数时候,代码运行良好并输出:

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

然而,每五六次我运行一次代码,我只得到以下输出:

Hello from main thread! 00:00:01.1017591

并且Task中Wait之后的代码永远不会被调用。

我在Windows Server 2012 R2Visual Studio 15.4.1上使用.NET Core 2.0.2

有人能重现这种行为吗?

有人能确认我的代码是否正确,或者是否有任何问题吗?

更新在@ArhiChief建议在Release配置中测试结果后,我发现只有当我使用IDE调试代码时,问题才会出现。

当我在调试/发布配置的命令行中构建和运行代码时,似乎没有问题。

我试着关闭/重新打开IDE,清理项目并进行新的重建,现在IDE似乎也工作得很好。

结果:在重新启动IDE、清理项目并重新构建项目后,到目前为止我还没有遇到这个问题。我怀疑IDE中有个小错误。但是我不能报告它,因为它现在已经不见了。

我将保留这个问题,以防其他人遇到这个问题并希望跟踪和报告错误。

我也知道你的第一个任务可能会被处理和收集。考虑这个代码

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

我收到消息Hello from the Main thread! 00:00:01.0111623。我也读过

对Set()的单个调用表示事件,并且释放任何等待的Task。在调用Reset()方法之前,对Wait()的新调用不会被阻止。

但让我们回到我们的代码。如果你像这个一样重写它

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

你会发现一切都如你所料。

最新更新