title: Should I have multiple threads when using FileSystemWatcher?
body: <p>I have an MVC3 web app via which users upload text files to the APP Data/Upload folder on a server.  The requirement is to transfer these newly uploaded files to a folder on another server through FTP. I used a FileSystemWatcher in a Console Application which monitors this Upload folder. When a file is created fully, I transfer this newly generated file to the FTP folder.  </p>
  
  <p>My concern is that if multiple instances/users upload the file from the web application, how would my console application handle that scenario? For instance, do I need to have a queue and process the files on a different thread using for example the <code>FileProcesser</code> below?</p>
  
  <pre><code>public class FileProcessor
  {
      private readonly Queue&lt;string&gt; files = new Queue&lt;string&gt;();
      private Thread thread;
      private readonly EventWaitHandle waitHandle = new AutoResetEvent(true);
      private static readonly object lockObject = new object();
  
      private volatile bool shouldStop = false;
  
      #region Helper methods
  
      private static bool IsFileUploadComplete(string path)
      {
          try
          {
              using (File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None))
              {
                  return true;
              }
          }
          catch (IOException)
          {
              return false;
          }
      }
  
      private void ProcessFile(string path)
      {
          // Check if Result file has been completely created / uploaded
          int maximumProcessRetries = 5;
          int delayBeforeRetry = 5000; //in milliseconds, 5 seconds
  
          int attempts = 0;
  
          while (true)
          {
              if (IsFileUploadComplete(path))
              {
                  //1. Open in existing IE process on Instrument Workstation
                  var p = new System.Diagnostics.Process();
                  var s = new System.Diagnostics.ProcessStartInfo(Settings1.Default.RSLSM_URL);
                  s.UseShellExecute = true;
                  s.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
                  p.StartInfo = s;
                  p.Start();
  
                  //2. Open in new IE process on Instrument workstation
                  //System.Diagnostics.Process.Start("IEXPLORE.EXE", "www.yahoo.com");
  
                  break;
              }
              attempts += 1;
              if (attempts &gt;= maximumProcessRetries)
              {
                  // Log error and send out notifications to RSLMS Database or Email RSLMS Admin group?
                  break;
              }
              Thread.Sleep(delayBeforeRetry);
          }
  
          // Add any logic after the file has been processed
          //File.Delete(path);
      }
  
      private void Work()
      {
          while (!shouldStop)
          {
              string path = String.Empty;
              lock (lockObject)
              {
                  if (files.Count &gt; 0)
                  {
                      path = files.Dequeue();
                  }
              }
  
              if (!String.IsNullOrEmpty(path))
              {
                  // Process the file
                  ProcessFile(path);
              }
              else
              {
                  // If no files are left to process then wait
                  waitHandle.WaitOne();
              }
          }
      }
  
      #endregion
  
      #region Methods
  
      public void EnqueueFile(string path)
      {
          // Queue the file
          lock (lockObject)
          {
              files.Enqueue(path);
          }
  
          // Initialize and start the worker thread when the first file is queued
          // or when it has been stopped and thus terminated.
          if (thread == null || shouldStop)
          {
              thread = new Thread(new ThreadStart(Work));
              thread.Start();
          }
          // If the thread is waiting then start it
          else if (thread.ThreadState == ThreadState.WaitSleepJoin)
          {
              waitHandle.Set();
          }
      }
  
      public void StopProcessing()
      {
          shouldStop = true;
      }
  
      #endregion
  }
  </code></pre>