On further investigation, (mostly from reading the badly documented code), I discovered the flow and pattern of the program.
- The parent thread is only there to parse command line args, create shared variables etc.
- One thread scans the filing system looking for jobs to do. The job objects are placed into a shared queue.
- Then a variable number of worker threads (up to 30 of them) pop items from the queue of jobs and do the work.
- There was a slight complexity where the workers signal to the work finding thread via a semaphore, so that once the queue has enough jobs in it, the work finding thread pauses until the workers signal that they are idle.
Once I figured out what was going on, it was easier to debug, I simply hacked the code a bit so that queue was populated with a small number of jobs, and then a single worker thread was started.