WaitHandles 的数目必须少于或等于 64 个 当开启的ManualResetEvent 实例数据大于64个之后,系统就会抛出此错误。
但在实际项目中,我需要请求多线程的数量在很多情况下都会超过 64个,为了解决这个限制。 才用一个信号量来监控多个线程的方式实现,即可开启任意一个线程。
//1 首先自己封装一个 信号量类 :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace AutoGenMarketPriceData.BLL
{
/// <summary>
/// 多线程信号等待
/// </summary>
public class MultiThreadResetEvent : IDisposable
{
private readonly ManualResetEvent done;
private readonly int total;
private long current;
/// <summary>
/// 监视total个线程执行(线程数固定,可以超过64个)
/// </summary>
/// <param name="total">需要等待执行的线程总数</param>
public MultiThreadResetEvent(int total)
{
this.total = total;
current = total;
done = new ManualResetEvent(false);
}
/// <summary>
/// 线程数不固定,监视任意线程数时
/// </summary>
public MultiThreadResetEvent()
{
done = new ManualResetEvent(false);
}
/// <summary>
/// 加入一个要等待的线程信号
/// </summary>
public void addWaitOne()
{
Interlocked.Increment(ref current);
}
/// <summary>
/// 唤醒一个等待的线程
/// </summary>
public void Set()
{
// Interlocked 原子操作类 ,此处将计数器减1
if (Interlocked.Decrement(ref current) == 0)
{
//当所以等待线程执行完毕时,唤醒等待的线程
done.Set();
}
}
/// <summary>
/// 等待所以线程执行完毕
/// </summary>
public void WaitAll()
{
done.WaitOne();
}
/// <summary>
/// 释放对象占用的空间
/// </summary>
public void Dispose()
{
((IDisposable)done).Dispose();
}
}
}
//2 调用示例
public void BeginGeneratePriceDatas()
{
#if !DEBUG
//设置10个线程
ThreadPool.SetMaxThreads(10, 10);
MultiThreadResetEvent threadEvent = new MultiThreadResetEvent();
#endif
foreach (Area bsyArea in bsyAreaLists)
{
foreach (Menu menu in menuList)
{
#if DEBUG
//debug使用单线程方便调试
DoTaskOneThread(bsyArea, menu);
#else
//release 版本使用多线程处理
threadEvent.addWaitOne(); //加入一个需要监控的线程
ThreadModel model = new ThreadModel()
{
BsyArea = bsyArea,
BsyMenu = menu,
CurrentWaitHandle = threadEvent
};
ThreadPool.QueueUserWorkItem(new WaitCallback(DoTask), model);
#endif
}
}
#if !DEBUG
threadEvent.WaitAll();
threadEvent.Dispose();
#endif
}
//在该方法中,线程执行完毕,减少监控的线程
public void DoTask(object state)
{
//AutoResetEvent are = (AutoResetEvent)state;
ThreadModel currentModel = (ThreadModel)state;
MultiThreadResetEvent are = (MultiThreadResetEvent)currentModel.CurrentWaitHandle;
Area bsyArea = currentModel.BsyArea;
Menu menu = currentModel.BsyMenu;
DoTaskOneThread(bsyArea, menu);
are.Set();
}
// 可以参照我的调用示例 自己修改下。