Consolidate the mutexes which covered root-related interactions.  I had thought I could get away with decoupling the raw and processed files, but so far that hasn't been the case.
Add a watch for the time required by the main thread to acquire a RootInterface lock.  This turns out to be dominant, indicating the FinishEvent thread is starving the compute threads.
Force FinishEventsThread to wait for a sufficient number of events to accumulate on the queue before continuing.  This is superior to the previous option of waiting a fixed amount of time before beginning work.
Retract an earlier comment -- it does seem acceptable to use raw and processed trees simultaneously.  This is very good, because letting the raw tree block AcceptEvent was starving it.
In case an event actually won't be denoised, skip straight to outputting it rather than putting it on the queue.  This saves lots of locking and unlocking operations, and allows us to combine two actions which would be forced to run in serial anyway.