最近因为工作原因涉及到多线程编程,学到的心得在这里记录下来与大家分享,如有不正确的地方欢迎指出。
AutoResetEvent与ManualResetEvent是C#中线程通信使用的两种信号量,他们都通过调用WaitOne函数来等待信号,通过调用Set来释放其他等待中的线程,通过调用Reset来重新阻止其他线程。
他们的构造函数相似,均接受一个bool类型参数,指示初始状态。
public AutoResetEvent ( bool initialState )
public ManualResetEvent( bool initialState )
当构造参数为true时,信号为终止状态,允许一个或多个等待线程继续;当构造参数为false时,信号为非终止状态,导致线程阻止。AutoResetEvent与ManualResetEvent的区别在于,AutoResetEvent的Set信号被另一线程接收后,其会自动重置为阻止状态,而ManualResetEvent并不会自动重置,他将保持非阻止状态。即AutoResetEvent一次只能唤醒一个线程,而ManualResetEvent一次将唤醒所有等待的线程。
下面我们用这样一个例子来说明两者的区别,在下面的程序中,thread1和thread2均等待同一个信号量resetEvent。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace ThreadDemo{ class Program { static AutoResetEvent resetEvent; static void thread_call() { string name = Thread.CurrentThread.Name; resetEvent.WaitOne(); Console.Out.WriteLine("Thread {0} is called.", name); } static void Main(string[] args) { resetEvent = new AutoResetEvent(false); Thread thread1 = new Thread(thread_call); thread1.Name = "Thread_1"; Thread thread2 = new Thread(thread_call); thread2.Name = "Thread_2"; thread1.Start(); thread2.Start(); Thread.Sleep(2000); Console.Out.WriteLine("Set 1st"); resetEvent.Set(); Thread.Sleep(2000); Console.Out.WriteLine("Set 2nd"); resetEvent.Set(); Console.ReadKey(); } } }
两个子线程启动后均在等待resetEvent,故均阻塞在WaitOne处。
两秒后主线程第一次调用Set,此时thread2被唤起,由于resetEvent是AutoResetEvent,故其自动重置,thread1不会被唤起。
主线程第二次调用Set,此时thread1被唤起。
输出如下:
若将以上程序中的AutoResetEvent换为ManualResetEvent,主线程第一次调用Set时,两线程均被唤起。Set 1st Thread Thread_1 is called. Set 2nd Thread Thread_2 is called.
输出如下:
Set 1st Thread Thread_1 is called. Thread Thread_2 is called. Set 2nd