ManualResetEvent是C#中一個比較常用的工具,可用於線程間通信,實現一種類似信號量的功能。
這里的信號量與Java中的信號量Semaphore不同。
Java中的信號量Semaphore,是控制有限資源的並發訪問。
這里的ManualResetEvent,更像是一種線程擋板。
先了解一下ManualResetEvent的基本用法:
1、初始化:public ManualResetEvent(bool initialState);
ManualResetEvent的構造方法有個bool型參數,當為true時,則表示有信號,為false時,則表示無信號。
這個怎么理解呢?我們接着看ManualResetEvent3個基本方法中的WaitOne方法。
2、WaitOne方法:WaitOne方法有幾種4種重載,我在這里只對它的功能進行分析。
WaitOne方法,顧名思義,它會具有一種等待的功能,也就是線程阻塞。
這里的阻塞功能是有條件的,當無信號時,它是阻塞的,有信號時,它將無任何阻塞,被執行時就直接跳過了。
所以,回顧到1,當初始化ManualResetEvent時,initialState為false,WaitOne將會有阻塞效果,否則,沒有阻塞效果。
3、Set方法:將ManualResetEvent對象的信號狀態設為有信號狀態,
這個時候WaitOne如果正在阻塞中的話,將會立即終止阻塞,向下繼續執行。
而且這個狀態一直不變的話,每次執行到WaitOne都將無任何阻塞。
4、Reset方法:
將ManualResetEvent對象的信號狀態設為無信號狀態,當下次執行到WaitOne時,又將重新開始阻塞。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ThreadTest
{
class Program
{
static void Main(string[] args)
{
new ProductAndCostTester();
}
}
/// <summary>
/// 生產消費模型
/// </summary>
public class ProductAndCostTester
{
/// <summary>
/// 生產線1線程
/// </summary>
private Thread _producterThread1;
/// <summary>
/// 生產線2線程
/// </summary>
private Thread _producterThread2;
/// <summary>
/// 消費線線程
/// </summary>
private Thread _costerThread;
/// <summary>
/// 產品列表
/// </summary>
private List<int> _goodList;
/// <summary>
/// ManualResetEvent實例
/// </summary>
private ManualResetEvent _mre;
public ProductAndCostTester()
{
_goodList = new List<int>();
_mre = new ManualResetEvent(false);//false初始化狀態為無信號,將使WaitOne阻塞
_producterThread1 = new Thread(Product1);
_producterThread1.Name = "Productor1";
_producterThread1.Start();
_producterThread2 = new Thread(Product2);
_producterThread2.Name = "Productor2";
_producterThread2.Start();
_costerThread = new Thread(Cost);
_costerThread.Name = "Costor";
_costerThread.Start();
}
/// <summary>
/// 生產線1
/// </summary>
void Product1()
{
while (true)
{
Console.WriteLine(Thread.CurrentThread.Name + ":" + DateTime.Now.ToString("HH:mm:ss"));
for (int i = 0; i < 3; i++)
{
_goodList.Add(1);
}
_mre.Set();//表示有信號了,通知WaitOne不再阻塞
Thread.Sleep(8000);
}
}
/// <summary>
/// 生產線2
/// </summary>
void Product2()
{
while (true)
{
Console.WriteLine(Thread.CurrentThread.Name + ":" + DateTime.Now.ToString("HH:mm:ss"));
for (int i = 0; i < 6; i++)
{
_goodList.Add(1);
}
_mre.Set();//表示有信號了,通知WaitOne不再阻塞
Thread.Sleep(10000);
}
}
/// <summary>
/// 消費線
/// </summary>
void Cost()
{
while (true)
{
if (_goodList.Count > 0)
{
Console.WriteLine("Cost " + _goodList.Count + " at " + DateTime.Now.ToString("HH:mm:ss"));
_goodList.Clear();
_mre.Reset();//重置為無信號了,使WaitOne可以再次阻塞
}
else
{
Console.WriteLine("No cost at " + DateTime.Now.ToString("HH:mm:ss"));
_mre.WaitOne();//如果沒有可消費的產品,即無信號,則會阻塞
}
}
}
}
}

