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;
}
}
}
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)