Search code examples
c#multithreadingthread-safetythreadpoolfilesystemwatcher

c# ThreadPool using less threads than cores because of memory restrictions with FileSystemWatcher


I have an extensive image calculation task which uses about 1GB of memory (one calculation cycle takes about 4 seconds). I process those images automatically when they arrive in the folder using a FileSystemWatcher. When the FileSystemWatcher fires an event for a new file I queue the work in the eventhandler method with:

private void OnNewFileInDir(object source, FileSystemEventArgs evtArgs)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessTheNewImage), evtArgs.FullPath); 
}

My problem is that the program crashes on a regular basis when the files arrive quickly. In the debug window I can see that neary 3GB memory are used in that moment. When I use smaller images in order to use less memory, there are no crashes (so far).

My question: What can I do to use less (maybe just 2) threads independent of cores of my computer?

Or is my approach of using a FileSystemWatcher to cue new files to a thread pool completely stupid? I am not at all experienced with thread races or similar things. So, furthermore: Does that look threadsafe?

Thanks a lot upfront and all the best

Tim

For completeness here is the code executed by the threads (a bit simplified for ease of reading):

private void ProcessTheNewImage(object threadFilenameInfo)
{
   String filename = (String)threadFilenameInfo;

   // Load the image
   Image currentImage = Image.FromFile(filename);

   //Calculate the image in an external DLL
   Image currentResultImage = ImageProcessing.getResultImage(currentImage);

   //Create the filename with the result infos
   string saveFileName = "blahblah";

   //Save the image
   currentResultImage.Save(saveFileName);

   //dispose the images
   currentImage.Dispose();
   currentResultImage.Dispose();
}

Solution

  • The Threadpool has only a very limited form of resource management. It will slowly keep adding threads when the queue fills up. It is meant for relatively small (< 500 ms) jobs. There is no safety-valve to stop it from clogging up your application.

    You could create a workflow for this: the watcher event pushes simple datapackets into a ConcurrentQueue and then you create 2 or more Threads (better: Tasks) to process the queue. This will allow you to tune the number of threads.