3

C#AutoResetEvent和ManualResetEvent介绍

 1 year ago
source link: https://www.mihu.live/archives/384/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

AutoResetEvent

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

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

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():将事件设置为已发送信号状态,对于AutoResetEvent来说允许所有正在等待的线程继续执行

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.ManualResetEvent在调用Set()后WaitOne()将失效,不再进行线程阻塞,需要重新阻塞的话要调用Reset(),但AutoResetEvent不需要。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK