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)