代码改变世界

WaitHandles 的数目必须少于或等于 64 个--任意线程信号量监视

2013-05-23 17:25  Spring.Guo  阅读(1483)  评论(0编辑  收藏  举报

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();
     }

 

// 可以参照我的调用示例 自己修改下。