前言
在实际的开发过程中,经常需要使用很多子线程来实现某些功能需求,有时候当主线程分配的任务过多或做一些需要长时间等待和响应的工作时单独使用子线程来实现可能更好,可是当我们程序中的子线程太多的时候,有些需求就需要在线程之间进行通讯或者传递消息。那么对于C#来说,是如何实现线程间通讯的。
一、AutoResetEvent
介绍
AutoResetEvent表示信号量,可用于线程间发送信号互相通讯,线程通过调用WaitOne来等待信号。
如果AutoResetEvent为非终止状态,则线程会被阻止,并等待当前控制资源的线程(主线程)调用Set()发出资源可用的信号时释放等待线程。此时AutoResetEvent将保持终止状态,直到一个正在等待的线程被释放,然后自动返回非终止状态。如果没有任何线程在等待,则状态将无限期的保持为终止状态。
AutoResetEvent可在声明时,传递布尔值到构造函数,初始化其初始状态。若初始状态为终止状态则为true,否则为false。
简单解释就是非终止状态下子线程在使用AutoResetEvent在方法WainOne时需要等待AutoResetEvent的信号,否则不往下继续执行,无信号则一直等待。终止状态就是无需等待直接可以顺序执行。
//初始化为非终止状态
private AutoResetEvent threadOne = new AutoResetEvent(false);
常用方法
Set(): 表示AutoResetEvent发送信号,在主线程或者掌握资源的线程中使用。
WaitOne(): 等待信号,在子线程中使用,如果初始化的AutoResetEvent默认为非终止状态,当子线程运行到WaitOne()程序时,则线程等待,后面的不执行。直到Set()信号发出,才顺序执行。
Demo案例
假设我去书店买书,选中书后需要先去缴费处付钱,付完钱后去仓库取书,走就行。
在此业务中我属于主线程,收费处和仓库为子线程。
主线程
const int num = 400;
//默认为非终止状态,必须得等待信号量。
static AutoResetEvent threadPayMoneyOne = new AutoResetEvent(false);
static AutoResetEvent threadGetBookTwo = new AutoResetEvent(false);
static int number;
static void Main(string[] args)
{
Thread PaymoneyThread = new Thread(new ThreadStart(PayMoneyOne));
PaymoneyThread.Name = "缴费线程";
PaymoneyThread.Start();
Thread GetBookThread = new Thread(new ThreadStart(GetBookTwo));
GetBookThread.Name = "仓库线程";
GetBookThread.Start();
for (int i = 0; i < num; i++)
{
Console.WriteLine("买书主线程:数量 "+i);
number = i;
//主线程通知两个子线程
threadPayMoneyOne.Set();
threadGetBookTwo.Set();
Thread.Sleep(0);
}
PaymoneyThread.Abort();
GetBookThread.Abort();
Console.ReadKey();
}
子线程
/// <summary>
/// 缴费处
/// </summary>
static void PayMoneyOne()
{
while (true)
{
threadPayMoneyOne.WaitOne();
Console.WriteLine("Thread Name=" + Thread.CurrentThread.Name + ",number:" + number);
Thread.Sleep(0);
}
}
/// <summary>
/// 仓库处
/// </summary>
static void GetBookTwo()
{
while (true)
{
threadGetBookTwo.WaitOne();
Console.WriteLine("Thread Name="+Thread.CurrentThread.Name+",number:"+number);
Thread.Sleep(0);
}
}
验证图片
可以发现当在主线程中循环的调用两个子线程的Set()方法后,子线程就会立即执行,否则就等待不往下执行。
利用AutoResetEvent中的Set()和WaitOne()来进行线程间的通讯,在日常的软件开发中可以帮助我们更好的实现更加复杂的业务。
二、ManualResetEvent
ManualResetEvent和AutoResetEvent都可用作线程间通讯的,字面意思看看到ManualResetEvent是手动通讯,AutoResetEvent是自动的。
两者用法基本一样,最最根本的不同是,AutoResetEvent在子线程中调用完WaitOne()方法后,AutoResetEvent就又进入到了非终止状态,其它调用了WaitOne的线程则必须继续等待。而ManualResetEvent则不同,它在调用完WWaitOne后不更改ManualResetEvent信号量的状态,其余调用WainOne的线程也可以收到信号。
若要使得ManualResetEvent和AutoResetEvent保持一致的行为,则在ManualResetEvent调用完WainOne后,再次调用Reset就可更改信号量状态。
小寄语
人生短暂,我不想去追求自己看不见的,我只想抓住我能看得见的。
原创不易,给个关注。
我是阿辉,感谢您的阅读,如果对你有帮助,麻烦点赞、转发 谢谢。