分析.NET中的CountDownLatch类

开发 后端
本文将分析.NET中的CountDownLatch类,透过作者在实际工作中碰到的有N个互不相关的任务要在线程池中跑,但有一个线程要等待N个任务完成之后才能继续的问题,为大家简单介绍下。

最近笔者在用.Net写程序时遇到一个问题:有N个互不相关的任务要在线程池中跑,但有一个线程要等待N个任务完成之后才能继续。而这个N是个未知数,可能会 很大(因此才会想到使用线程池而不是手动去new一个therad)。翻了翻.Net类库的文档,发现一个叫WaitHandle的类。这个类的用法挺有 意思,需要为每个线程创建一个WaitHandle对象并把它们放在一个数组中,然后用WaitHandle类中的WaitAll方法来等待这些 WaitHandle被调用Set方法。(代码就不写了,可以参考MSDN http://msdn.microsoft.com/zh-cn/library /system.threading.waithandle.aspx)

虽然觉得这有点复杂,但还是试了试。当程序运行时,碰到了一个问 题,如果WaitHandle数组超过64个元素之后,WaitHandle对象的WatiAll方法罢工了。后来为了程序能运行,只得想了一个笨办法: 先创建两个WaitHandle对象放在数组,然后用循环两个两个地运行任务。代码的思路大概是下面这样:

WaitHandle[] handles = new WaitHandle[]{
    new AutoResetEvent(false),
    new AutoResetEvent(false)
};
int times = (int)N/2;
int i;
for(i = 0; i < times; i++){
    ThreadPool.QueueUserWorkItem(new WaitCallback(Tasks[i*2]), handles[0]);  
    ThreadPool.QueueUserWorkItem(new WaitCallback(Tasks[i*2+1]), handles[1]);
    WaitHandle.WaitAll(handles);
}
if(i*2 < N){
    ThreadPool.QueueUserWorkItem(new WaitCallback(Tasks[i*2 + 1]), handles[0]);
    WaitHandle.WaitAny(handles);
}

虽然代码这么写比较复杂,但至少可以保证运行时不会出问题。但这么写代码显然并不KISS!于是问了问高手,说有个 RegisterWaitForSingleObject方法,但一看这个方法的参数列表就够让人晕的了。有点怀念Java了,记得Java中有个 CountDownLatch类,创建类的时候赋一个初始值X,然后主线程中调用await,线程池中跑的线程调用countDown方法。就可以实现主 线程等待X次countDown方法调用之后继续。这样既没有64个WaitHandle的限制,也不用去研究那个 RegisterWaitForSingleObject方法。不过问题在于.Net中并没有这么一个东西,只能自己动手了。

class CountDownLatch {
    private object lockobj;
    private int counts;

    public CountDownLatch(int counts){
        this.counts = counts;
    }

    public void Await(){
        lock(lockobj){
            while(counts > 0){
                Monitor.Wait(lockobj);
            }
        }
    }

    public void CountDown(){
        lock(lockobj){
            counts--;
            Monitor.PulseAll(lockobj);
        }
    }
}

有了这个东西,上面的代码可以改的更少一些。


CountDownLatch cdl = new CountDownLatch(N);
for(int i = 0; i < N; i++){
     ThreadPool.QueueUserWorkItem(new WaitCallback(Tasks[i]), cdl);
}
cdl.Awati();

而对于任务的代码来说,在结尾处吧对WaitHandle的Set方法的调用改为对CountDownLatch类的CountDown方法的调用即可。
最后,我想说的是其实没必要把思路都拘束在.Net上或者Java上,相互借鉴会让思路更开阔一些。不过有句心里话想说的就是,其实Java的类库在某些方面做的比.Net好一些。

【编辑推荐】

  1. 部署和分发.NET应用程序的两种方法
  2. 详解.NET编程过程中的线程冲突
  3. 作为ASP.NET开发人员必须养成的编程习惯
责任编辑:彭凡 来源: cnblogs
相关推荐

2021-09-08 06:51:53

CountDownLa闭锁源码

2016-08-31 16:07:54

Python实例

2009-10-15 10:57:16

VB.NET Text

2009-08-04 17:42:23

DataSourceCASP.NET

2009-02-27 08:56:30

IIS.Net原理分析

2009-09-02 18:28:55

.NET框架ESBasic

2022-03-29 07:20:04

密封类.NET性能

2009-07-22 18:08:00

ASP.NET基类

2024-04-07 09:04:18

Parallel 类编程工具.NET

2009-08-05 18:42:05

xsd.exe

2009-12-18 17:25:21

ADO.NET类库

2009-10-12 09:02:03

SmartRWLock

2009-10-23 10:58:33

VB.NET条件语句

2009-11-04 14:54:51

.NET类

2009-10-30 10:58:45

VB.NET创建类

2011-06-21 09:22:53

Random类

2010-06-18 09:23:33

SortedSet.NET 4

2009-08-25 14:03:17

2021-08-30 19:00:46

静态CompletableCountDownLa

2019-07-02 15:21:39

缓存NET单线程
点赞
收藏

51CTO技术栈公众号