views:

204

answers:

1

I have this application that will recurse all folders in a given directory and look for PDF. If a PDF file is found, the application will count its pages using ITextSharp. I did this by using a thread to recursively scan all the folders for pdf, then if then PDF is found, this will be queued to the thread pool. The code looks like this:

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

My problem is, how do i know that the thread pool's thread has finished processing all the queued items so i can tell the user that the application is done with its intended task?

+4  A: 

Generally I would do something like this by having a counter variable. For each work item you queue in the ThreadPool add one to the counter variable. Then when it is processed you would decrease the counter variable.

Be sure that you do the incrementing and decrementing via the methods on the Interlocked class as this will ensure that things are done in a thread-safe manner.

Once the counter hits zero you could flag that the tasks are completed using a ManualResetEvent

If you have access to .NET 4 then you can use the new CountdownEvent class to do a similar thing.

JonC
I have done a similar logic to this. Only i used the ThreadPool.GetAvailableThreads. I set the MaxThreads the pools should be using by 20. So at the last of the task i checked if the available threads are equal to the max that i set. Unfortunately this fails. I will research on that Manual Reset Event.
mcxiand
@mcxiand: You can't use the ThreadPool counters because other code (lib) could create threads and the TP is recycling/deleting them.
Henk Holterman
@Henk Holterman: Is that so? From what i understood is that, the ThreadPool will be queued of task by QueueUserWorkItem method. Can you give more details about your comment? it would be very much appreciated.
mcxiand
@mcxiand: You have no way of guaranteeing that all the threads in the ThreadPool will be free once you have finished processing your items.It may well be the case that all threads become available once your items are processed, but there is one ThreadPool per process, so any other code that is loaded may well be using the ThreadPool to do things at the same time and your code should never rely on assumptions about the numbers of threads.
JonC
I agree with Jonc here.
Henk Holterman
thank you very much for the explanation. I already understood it. I also changed my code as what JonC said above.
mcxiand