C#学习 - 关于AutoResetEvent和ManualResetEvent

在.Net多线程编程中,AutoResetEvent 和 ManualResetEvent 这两个类经常用到,他们的用法很类似,但也有区别。

Set方法将信号置为发送状态,Reset()方法将信号置为不发送状态,WaitOne()等待信号的发送。可以通过构造函数的参数值来决定其初始状态,若为true则非阻塞状态,为false为阻塞状态。如果某个线程调用WaitOne()方法,则当信号处于发送状态时,该线程会得到信号, 继续向下执行。

二者区别在于调用后,AutoResetEvent.WaitOne()每次只允许一个线程进入,当某个线程得到信号后,AutoResetEvent会自动又将信号置为不发送状态,则其他调用WaitOne()的线程只有继续等待。也就是说,AutoResetEvent一次只唤醒一个线程而ManualResetEvent则可以唤醒多个线程。因为当某个线程调用了ManualResetEvent.Set()方法后,其他调用WaitOne()的线程获得信号得以继续执行,而ManualResetEvent不会自动将信号置为不发送。也就是说,除非手工调用了ManualResetEvent.Reset()方法,则ManualResetEvent将一直保持有信号状态,ManualResetEvent也就可以同时唤醒多个线程继续执行。

 - 本质上AutoResetEvent.Set()方法相当于ManualResetEvent.Set()+ManualResetEvent.Reset();

 - 因此AutoResetEvent一次只能唤醒一个线程,其他线程还是堵塞

下面举例说明:

1. AutoResetEvent

static AutoResetEvent ev = new AutoResetEvent(false);
static int count = 0;
static void ProcessingFunc()
{
	while (true)
	{
		if (ev.WaitOne(20))
		{
			Console.WriteLine("1 Signal Processed!");
			if (Interlocked.CompareExchange(ref count, 0, 10) == 10)
				break;
		}
	}
}
...
static void Main(string[] args)
{
	var processor = new Thread(ProcessingFunc);
	processor.Start();

	for (int i = 0; i < 10; i++)
	{
		Thread.Sleep(1000);
		Interlocked.Increment(ref count);
		ev.Set();
		Console.WriteLine("Set Signal!");
	}
}

2. ManualResetEvent

private static ManualResetEvent mre = new ManualResetEvent(false);

private static void ThreadProc()
{
	string name = Thread.CurrentThread.Name;
	Console.WriteLine(name + " starts and calls mre.WaitOne()");
	mre.WaitOne();
	Console.WriteLine(name + " ends.");
}

static void Main()
{
	Console.WriteLine("\nStart 2 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 threads have started, press Enter to call Set()" + "\nto release all the threads.\n");
	Console.ReadLine();

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

猜你喜欢

转载自blog.csdn.net/jianhui_wang/article/details/80584250
今日推荐