C#AutoResetEvent和ManualResetEvent介绍
侧边栏壁纸
  • 累计撰写 35 篇文章
  • 累计收到 131 条评论

C#AutoResetEvent和ManualResetEvent介绍

who
who
2022-11-28 / 0 评论 / 157 阅读 / 正在检测是否收录...

AutoResetEvent和ManualResetEvent是c#用来线程同步的。

AutoResetEvent

参考:https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.autoresetevent?view=net-7.0

Set():将事件设置为已发送信号状态,对于AutoResetEvent来说允许一个正在等待的线程继续执行。如果没有线程在等待,将保持无限期有信号状态。

WaitOne():处于无信号状态时,阻塞当前线程直到接收到了信号量

如果线程在处于信号状态时AutoResetEvent调用WaitOne,则线程不会阻塞。AutoResetEvent立即释放线程并返回到无信号状态。也就是说如果没有线程在WaitOne,先执行了Set,会导致后调用的第一次WaitOne失效不阻塞,第二次调用WaitOne阻塞会生效

using System;
using System.Threading;

namespace AutoResetEvent_Examples
{
    class MyMainClass
    {
      const int numIterations = 100;
      static AutoResetEvent myResetEvent = new AutoResetEvent(false);
      static int number;
      
      static void Main()
        {
         //定义线程并启动,MyReadThreadProc方法接收到信号量后读取当前线程的名字和number并打印
         Thread myReaderThread = new Thread(new ThreadStart(MyReadThreadProc));
         myReaderThread.Name = "ReaderThread";
         myReaderThread.Start();
         for(int i = 1; i <= numIterations; i++)
         {
            Console.WriteLine("Writer thread writing value: {0}", i);
            number = i;
            
            //Signal that a value has been written.
            //调用Set()后MyReadThreadProc()从WaitOne()继续执行
            myResetEvent.Set();
            
            //Give the Reader thread an opportunity to act.
            Thread.Sleep(1);
         }

         //Terminate the reader thread.
         myReaderThread.Abort();
      }

      static void MyReadThreadProc()
      {
         while(true)
         {
            //The value will not be read until the writer has written
            // at least once since the last read.
            myResetEvent.WaitOne();
            Console.WriteLine("{0} reading value: {1}", Thread.CurrentThread.Name, number);
         }
      }
    }
}

官网拷贝的代码,只有当Main()中的for循环调用myResetEvent.Set(),MyReadThreadProc()才会收到信号来读取当前线程的名字,否则就会一直停在myResetEvent.WaitOne()而不会继续向后执行。

ManualResetEvent

参考:https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.manualresetevent?view=net-7.0

Set():将事件设置为已发送信号状态,对于ManualResetEvent来说允许所有正在等待的线程继续执行

Reset():设置事件无信号,使能够继续阻塞线程

using System;
using System.Threading;

public class Example
{
    // mre is used to block and release threads manually. It is
    // created in the unsignaled state.
    private static ManualResetEvent mre = new ManualResetEvent(false);

    static void Main()
    {
        Console.WriteLine("\nStart 3 named threads that block on a ManualResetEvent:\n");
        //定义三个线程
        for(int i = 0; i <= 2; i++)
        {
            Thread t = new Thread(ThreadProc);
            t.Name = "Thread_" + i;
            t.Start();
        }

        Thread.Sleep(500);
        Console.WriteLine("\nWhen all three threads have started, press Enter to call Set()" +
                          "\nto release all the threads.\n");
        Console.ReadLine();
        //给信号使ThreadProc()中的WaitOne()之后的代码执行
        mre.Set();

        Thread.Sleep(500);
        Console.WriteLine("\nWhen a ManualResetEvent is signaled, threads that call WaitOne()" +
                          "\ndo not block. Press Enter to show this.\n");
        Console.ReadLine();

        for(int i = 3; i <= 4; i++)
        {
            Thread t = new Thread(ThreadProc);
            t.Name = "Thread_" + i;
            t.Start();
        }
        //ManualResetEvent在调用Set()之后,WaitOne()并不会阻塞线程,要想阻塞线程,需要调用Reset()使没有信号,才能够继续阻塞线程
        Thread.Sleep(500);
        Console.WriteLine("\nPress Enter to call Reset(), so that threads once again block" +
                          "\nwhen they call WaitOne().\n");
        Console.ReadLine();
        //调用Reset()后继续阻塞线程
        mre.Reset();

        // Start a thread that waits on the ManualResetEvent.
        Thread t5 = new Thread(ThreadProc);
        t5.Name = "Thread_5";
        t5.Start();

        Thread.Sleep(500);
        Console.WriteLine("\nPress Enter to call Set() and conclude the demo.");
        Console.ReadLine();

        mre.Set();

        // If you run this example in Visual Studio, uncomment the following line:
        Console.ReadLine();
    }

    private static void ThreadProc()
    {
        string name = Thread.CurrentThread.Name;

        Console.WriteLine(name + " starts and calls mre.WaitOne()");

        mre.WaitOne();

        Console.WriteLine(name + " ends.");
    }
}
/*

Start 3 named threads that block on a ManualResetEvent:

Thread_0 starts and calls mre.WaitOne()
Thread_1 starts and calls mre.WaitOne()
Thread_2 starts and calls mre.WaitOne()

When all three threads have started, press Enter to call Set()
to release all the threads.


Thread_1 ends.
Thread_0 ends.
Thread_2 ends.

When a ManualResetEvent is signaled, threads that call WaitOne()
do not block. Press Enter to show this.


Thread_3 starts and calls mre.WaitOne()
Thread_3 ends.
Thread_4 starts and calls mre.WaitOne()
Thread_4 ends.

Press Enter to call Reset(), so that threads once again block
when they call WaitOne().


Thread_5 starts and calls mre.WaitOne()

Press Enter to call Set() and conclude the demo.

Thread_5 ends.

*/

简单总结一下二者区别:

1.AutoResetEvent调用Set只给一个正在WaitOne的线程信号使之继续执行,ManualResetEvent调用Set会给所有正在WaitOne的线程信号使之继续执行

2.在调用Set后ManualResetEvent将保持有信号状态,WaitOne将失效,不再进行线程阻塞,需要重新阻塞的话要调用Reset,但AutoResetEvent(在已经有线程WaitOne的情况下)会自动返回到无信号状态。

0

评论 (0)

取消