为什么在C#中使用AutoResetEvent和ManualResetEvent时,我的代码输出为何不同?

时间:2018-09-12 19:42:02

标签: c# multithreading

我试图了解AutoResetEvent和ManualResetEvent之间的区别。现在,我了解到AutoResetEvent允许一组线程中的每个线程一个接一个地工作。例如,您只有一台打印机,而您有两个打印任务,则希望打印任务1在打印任务2开始之前完成。在这种情况下,您将要使用AutoResetEvent。如果您想通过一个事件唤醒一堆线程,则ManualResetEvent很有用。

现在,我正在尝试使用以下代码片段来了解它们的工作原理。

    static AutoResetEvent resetEvent = new AutoResetEvent(false);
    static void Main(string[] args)
    {
        Task task = Task.Run(() =>
        {
            GetDataFromServer(1);
        });

        Task.Run(() =>
        {
            GetDataFromServer(2);
        });


        //Send first signal to get first set of data from server 1 and server 2
        resetEvent.Set();
        //manualResetEvent.Reset();

        Thread.Sleep(TimeSpan.FromSeconds(2));
        //Send second signal to get second set of data from server 1 and server 2
        resetEvent.Set();

        Console.ReadLine();
    }

    static void GetDataFromServer(int serverNumber)
    {
        //Calling any webservice to get data
        Console.WriteLine("I get first data from server" + serverNumber);
        resetEvent.WaitOne();

        Thread.Sleep(TimeSpan.FromSeconds(2));
        Console.WriteLine("I get second data from server" + serverNumber);

        resetEvent.WaitOne();
        Console.WriteLine("All the data collected from server" + serverNumber);
    }

当我使用ManualResetEvent时,它会提供以下输出:

我从server1获得了第一笔数据

我从server2获得了第一笔数据

我从server1获得了第二个数据

从server1收集的所有数据

我从server2获得了第二个数据

从server2收集的所有数据

如果将ManualResetEvent更改为AutoResetEvent,则会得到不同的输出,并且“从服务器收集的所有数据”将永远不会打印出来:

我从server1获得了第一笔数据

我从server2获得了第一笔数据

我从server1获得了第二个数据

我从server2获得了第二个数据

似乎我仍然不太了解它们的工作原理。

问题:

  1. 为什么当我使用AutoResetEvent时,它们具有不同的输出,并且“从服务器收集的所有数据”语句从不打印出来?我调用Set()方法向线程发出信号,告知它们可以执行任务。

  2. 为什么在不调用reset()的情况下使用ManualResetEvent且输出与在reset()中使用的输出相同?

  3. 在使用AutoResetEvent和ManualResetEvent时,如何更改代码段以使其具有相同的输出?

1 个答案:

答案 0 :(得分:0)

简要回答您的问题:

  1. AutoResetEvent在允许一个线程通过后自动重置。在上面的代码中,您要调用WaitOne()四次,因此您需要进行四个相应的Set()调用。这就是为什么您看不到最后的语句打印的原因。线程正在等待信号。

  2. 手动重置事件必须先手动重置,然后才能开始阻塞线程。 Set方法释放所有等待的线程,然后在调用Reset之前有一个完成的竞赛。如果这些线程实际上在Reset之前完成,则结果将如指示。

  3. 您不能保证无论使用哪种行为,行为都是相同的。两者具有不同的行为,因此至少在某些时候将一个替换为另一个会产生不同的行为。