代码之家  ›  专栏  ›  技术社区  ›  mark vanzuela

如何知道所有线程池的线程是否已完成其任务?

  •  7
  • mark vanzuela  · 技术社区  · 14 年前

    我有一个应用程序,它将在给定的目录中重现所有文件夹,并查找PDF。如果找到PDF文件,应用程序将使用ITextSharp对其页面进行计数。我通过使用一个线程递归地扫描所有文件夹中的pdf来完成这项工作,然后如果找到pdf,就会将其排队到线程池中。代码如下:

    //spawn a thread to handle the processing of pdf on each folder.
                    var th = new Thread(() =>
                    {
                        pdfDirectories = Directory.GetDirectories(pdfPath);
                        processDir(pdfDirectories);
                    });
                    th.Start();
    
    
    
     private void processDir(string[] dirs)
            {
                foreach (var dir in dirs)
                {
                    pdfFiles = Directory.GetFiles(dir, "*.pdf");
                    processFiles(pdfFiles);
    
                    string[] newdir = Directory.GetDirectories(dir);
                    processDir(newdir);
                }
            }
    
    
    
    private void processFiles(string[] files)
            {
                foreach (var pdf in files)
                {
                    ThreadPoolHelper.QueueUserWorkItem(
                        new { path = pdf },
                        (data) => { processPDF(data.path); }
                        );
                }
            }
    

    我的问题是,我如何知道线程池的线程已经完成了对所有排队项目的处理,这样我就可以告诉用户应用程序已经完成了其预期的任务?

    2 回复  |  直到 14 年前
        1
  •  4
  •   JonC    14 年前

    一般来说,我会用一个计数器变量来做类似的事情。 对于您在中排队的每个工作项 ThreadPool 向计数器变量添加一个。 然后,当它被处理时,您将减少计数器变量。

    确保通过上的方法执行递增和递减操作。 Interlocked 类,因为这将确保以线程安全的方式进行操作。

    一旦计数器为零,您可以使用 ManualResetEvent

    如果您可以访问.NET 4,则可以使用 CountdownEvent 类来做类似的事情。

        2
  •  2
  •   Henk Holterman    14 年前

    1)如何知道所有线程是否完成?

    您必须让线程自己执行签入/签出操作,方法是将代码括在以下两个部分之间:

    Interlocked.Increment(ref jobCounter);
    // your code
    Interlocked.Decrement(ref jobCounter);
    

    如果这太过混乱了匿名委托,那么只需使用包装方法。您可能还需要添加异常处理。

    互锁方法仍然存在等待它变为0的问题,带有sleep()的循环是一个弱问题,但在本例中是可行的解决方案。

    2)您正在递归树查询器中启动线程。小心点,你可能创造了太多,这会损害性能。