Reputation: 399
Example program: Listen FileSystem events on some folder and print FileSystem events info to console when Timer event fires.
class Program
{
public static string location = @"D:\TestEvents";
public static double interval = 15000;
public static System.Timers.Timer timer;
public static List<string> listOfChanges = new List<string>();
static void Main(string[] args)
{
StartWatch();
StartTimer();
Console.ReadLine();
}
private static void StartWatch()
{
FileSystemWatcher Watcher = new FileSystemWatcher();
Watcher.Path = location;
Watcher.Created += new FileSystemEventHandler(OnFileCreatedOrDeleted);
Watcher.Deleted += new FileSystemEventHandler(OnFileCreatedOrDeleted);
Watcher.EnableRaisingEvents = true;
}
static void OnFileCreatedOrDeleted(object sender, FileSystemEventArgs e)
{
listOfChanges.Add(String.Format("Change Type: {0}, Name: {1}, Time: {2}", e.ChangeType, e.Name, DateTime.Now));
}
private static void StartTimer()
{
timer = new System.Timers.Timer();
timer.AutoReset = false;
timer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimerEpleased);
timer.Interval = interval;
timer.Start();
}
private static void OnTimerEpleased(object sender, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine("Timer event fired: " + DateTime.Now);
foreach (var item in listOfChanges)
{
Console.WriteLine(item);
}
Console.WriteLine();
listOfChanges.Clear();
timer.Interval = interval;
timer.Start();
}
}
Is it safe to access the same storage static List<string> listOfChanges
from both event handlers?
I don't really understand how events works underneath. Is it creates some global event handler queue and runs all event handlers one-by-one despite of event type? Or it creates different threads for each event handler type?
Edit:
I guess the best solution is to use BlockingCollection
with ConcurrentQueue
, so it should be like this:
public static BlockingCollection<string> listOfChanges = new BlockingCollection<string>();
static void OnFileCreatedOrDeleted(object sender, FileSystemEventArgs e)
{
listOfChanges.Add(String.Format("Change Type: {0}, Name: {1}, Time: {2}", e.ChangeType, e.Name, DateTime.Now));
}
private static void OnTimerEpleased(object sender, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine("Timer event fired: " + DateTime.Now);
while (listOfChanges.Count > 0)
{
string item;
bool b = listOfChanges.TryTake(out item);
if (b)
{
Console.WriteLine(item);
}
}
Console.WriteLine();
timer.Interval = interval;
timer.Start();
}
Upvotes: 2
Views: 638
Reputation: 1797
You should not assume, those event handlers would be invoked from a single thread. Neither documentation for FileSystemWatcher nor Timer mentions how exactly are those handlers invoked, so I would choose the safe way here and ensure on my own access to this list is synchronized.
Upvotes: 0
Reputation: 38555
Im not sure if FileSystemWatcher uses more than one thread but just to be safe wrap you access to the list in a
lock (listOfChanges)
{
//Code that reads or writes to the listOfChanges.
}
Upvotes: 0
Reputation: 619
A generic List is not thread safe. It will be possible that you will get an error when listOfChanges is traversed (in OnTimerEpleased), and a new entry would have added an entry to the list (OnFileCreatedOrDeleted). See http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx. Either you synchronize access to the list or use a built-in thread safe collection: http://msdn.microsoft.com/en-us/library/system.collections.concurrent.aspx
Upvotes: 2