Search code examples
c#backgroundworkerfilesystemwatcher

c# filesystemwatcher and backgroundworker


I want so sync my Folder, so i have 10 Filesystemwatcher and 4 Backgroundworkers. The idea is, that one watcher can call every of the 4 worker but i want that the watcher choose a active and free worker, the others should not be triggered.

Exp: worker 1 fired, 2-4 do not.

What am I doing wrong here?

Here is my Code

        private void watcher1_OnChanged(object source, FileSystemEventArgs e)
        {
            // File Name
            string file = e.FullPath;

            // refresh App.Config
            ConfigurationManager.RefreshSection("appSettings");

            // Check Worker Active
            bool worker1Active = Convert.ToBoolean(ConfigurationManager.AppSettings["worker1Active"]);
            bool worker2Active = Convert.ToBoolean(ConfigurationManager.AppSettings["worker2Active"]);
            bool worker3Active = Convert.ToBoolean(ConfigurationManager.AppSettings["worker3Active"]);
            bool worker4Active = Convert.ToBoolean(ConfigurationManager.AppSettings["worker4Active"]);

            // Watcher Nummer
            string watcherNr = "Watcher 1";

            // Arguments to call worker
            List<object> arguments = new List<object>();
            arguments.Add(file);
            arguments.Add(watcher1_destinationPath);
            arguments.Add(watcher1_sourcePath);
            arguments.Add(watcherNr);

            bool success = false;

            while (!success == true)
            {
                try
                {
                    using (Stream stream = new FileStream(file, FileMode.Open))
                    {

                            if (worker1Active == true && worker1.IsBusy != true)
                            {
                                worker1.RunWorkerAsync(arguments);
                                success = true;
                                break;
                            }

                            if (worker2Active == true && worker2.IsBusy != true)
                            {
                                worker2.RunWorkerAsync(arguments);
                                success = true;
                                break;
                            }

                            if (worker3Active == true && worker3.IsBusy != true)
                            {
                                worker3.RunWorkerAsync(arguments);
                                success = true;
                                break;
                            }

                            if (worker4Active == true && worker4.IsBusy != true)
                            {
                                worker4.RunWorkerAsync(arguments);
                                success = true;
                                break;
                            }
                    }
                }
                catch
                {
                    success = false;
                }
            }
        }

Solution

  • EDIT: Make sure to lock files during processing and check for a lock before processing. If you have multiple workers processing a single file you will run into problems. Just make sure you requeue the job when a file you want to process is locked. It will automatically requeue until it is unlocked. Ofcourse you need to take care of unlocking it again.

    Here is an example app using the ThreadPool: The ThreadPool is thread safe which means when it's doing it's work, it's doing it in different threads which will keep your UI responsive and not block.

    Have fun!

    using System;
    using System.IO;
    using System.Threading;
    
    namespace FileWatcherThreadApp
    {
        class Program
        {
    
            static void Main(string[] args)
            {
                FileSystemWatcher fileWatcher = new FileSystemWatcher(@"C:\Users\BertSinnema\watch");
    
                //Enable events
                fileWatcher.EnableRaisingEvents = true;
    
                //Add event watcher
                fileWatcher.Changed += FileWatcher_Changed;
                fileWatcher.Created += FileWatcher_Changed;
                fileWatcher.Deleted += FileWatcher_Changed;
                fileWatcher.Renamed += FileWatcher_Changed;
    
                var maxThreads = 4;
    
                // Times to as most machines have double the logic processers as cores
                ThreadPool.SetMaxThreads(maxThreads, maxThreads * 2);
    
    
                Console.WriteLine("Listening");
                Console.ReadLine();
    
            }
    
            //This event adds the work to the Thread queue
            private static void FileWatcher_Changed(object sender, FileSystemEventArgs e)
            {
                ThreadPool.QueueUserWorkItem((o) => ProcessFile(e));
            }
    
            //This method processes your file, you can do your sync here
            private static void ProcessFile(FileSystemEventArgs e)
            {
                // Based on the eventtype you do your operation
                switch (e.ChangeType)
                {
                    case WatcherChangeTypes.Changed:
                        Console.WriteLine($"File is changed: {e.Name}");
                        break;
                    case WatcherChangeTypes.Created:
                        Console.WriteLine($"File is created: {e.Name}");
                        break;
                    case WatcherChangeTypes.Deleted:
                        Console.WriteLine($"File is deleted: {e.Name}");
                        break;
                    case WatcherChangeTypes.Renamed:
                        Console.WriteLine($"File is renamed: {e.Name}");
                        break;
                }
            }
        }
    
    
    }
    

    If you want to wach multiple folders, you can simply add another FileSystemWatcher and hook the Created, Renamed, Changed and Deleted events to the same eventhandler (FileWatcher_Changed)