深入分析C# 线程同步

2020-06-17 15:01:08于丽

AutoResetEvent:

AutoResetEvent 构造函数可以传入一个bool类型的参数,false表示将AutoResetEvent对象的初始状态设置为非终止。如果为true标识终止状态,那么WaitOne方法就不会再阻塞线程了。但是因为该类会自动的将终止状态修改为非终止,所以,之后再调用WaitOne方法就会被阻塞。

WaitOne 方法如果AutoResetEvent对象状态非终止,则阻塞调用该方法的线程。可以指定时间,若没有获取到信号,返回false

set 方法释放被阻塞的线程。但是一次只可以释放一个被阻塞的线程。

class ThreadSafe 
{ 
 static AutoResetEvent autoEvent; 

 static void Main() 
 { 
 //使AutoResetEvent处于非终止状态
 autoEvent = new AutoResetEvent(false); 

 Console.WriteLine("主线程运行..."); 
 Thread t = new Thread(DoWork); 
 t.Start(); 

 Console.WriteLine("主线程sleep 1秒..."); 
 Thread.Sleep(1000); 

 Console.WriteLine("主线程释放信号..."); 
 autoEvent.Set(); 
 } 

 static void DoWork() 
 { 
 Console.WriteLine(" t线程运行DoWork方法,阻塞自己等待main线程信号..."); 
 autoEvent.WaitOne(); 
 Console.WriteLine(" t线程DoWork方法获取到main线程信号,继续执行..."); 
 } 

} 

输出

主线程运行...
主线程sleep 1秒...
  t线程运行DoWork方法,阻塞自己等待main线程信号...
主线程释放信号...
  t线程DoWork方法获取到main线程信号,继续执行...

ManualResetEvent

ManualResetEventAutoResetEvent用法类似。

AutoResetEvent在调用了Set方法后,会自动的将信号由释放(终止)改为阻塞(非终止),一次只有一个线程会得到释放信号。而ManualResetEvent在调用Set方法后不会自动的将信号由释放(终止)改为阻塞(非终止),而是一直保持释放信号,使得一次有多个被阻塞线程运行,只能手动的调用Reset方法,将信号由释放(终止)改为阻塞(非终止),之后的再调用Wait.One方法的线程才会被再次阻塞。

public class ThreadSafe
{
 //创建一个处于非终止状态的ManualResetEvent
 private static ManualResetEvent mre = new ManualResetEvent(false);

 static void Main()
 {
 for(int i = 0; i <= 2; i++)
 {
  Thread t = new Thread(ThreadProc);
  t.Name = "Thread_" + i;
  t.Start();
 }

 Thread.Sleep(500);
 Console.WriteLine("n新线程的方法已经启动,且被阻塞,调用Set释放阻塞线程");

 mre.Set();

 Thread.Sleep(500);
 Console.WriteLine("n当ManualResetEvent处于终止状态时,调用由Wait.One方法的多线程,不会被阻塞。");

 for(int i = 3; i <= 4; i++)
 {
  Thread t = new Thread(ThreadProc);
  t.Name = "Thread_" + i;
  t.Start();
 }

 Thread.Sleep(500);
 Console.WriteLine("n调用Reset方法,ManualResetEvent处于非阻塞状态,此时调用Wait.One方法的线程再次被阻塞");
 

 mre.Reset();

 Thread t5 = new Thread(ThreadProc);
 t5.Name = "Thread_5";
 t5.Start();

 Thread.Sleep(500);
 Console.WriteLine("n调用Set方法,释放阻塞线程");

 mre.Set();
 }


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

 Console.WriteLine(name + " 运行并调用WaitOne()");

 mre.WaitOne();

 Console.WriteLine(name + " 结束");
 }
}


//Thread_2 运行并调用WaitOne()
//Thread_1 运行并调用WaitOne()
//Thread_0 运行并调用WaitOne()

//新线程的方法已经启动,且被阻塞,调用Set释放阻塞线程

//Thread_2 结束
//Thread_1 结束
//Thread_0 结束

//当ManualResetEvent处于终止状态时,调用由Wait.One方法的多线程,不会被阻塞。

//Thread_3 运行并调用WaitOne()
//Thread_4 运行并调用WaitOne()

//Thread_4 结束
//Thread_3 结束

///调用Reset方法,ManualResetEvent处于非阻塞状态,此时调用Wait.One方法的线程再次被阻塞

//Thread_5 运行并调用WaitOne()
//调用Set方法,释放阻塞线程
//Thread_5 结束