Runtime exception using FileSystemWatcher - reproducible code included

L

lee

I've been using the FileSystemWatcher in Framework 1.1 and 2.0. I use
it to listen to the whole hard drive sometimes, so that I can maintain
a total of each directory size for quota features. Ussually it works
ok, but sometimes when there are a lot of changes at once, an exception
is throw, regardless of the FSW buffer size, and this exception is not
marshalled through the FSW error handler, it is thrown on a thread pool
thread which I can't trap. In Framework 1.1, the error would be
swallowed and I never knew about it which was bad enough, but Framework
2.0 now throws the exception and then the whole app crashes. An
example of when FSW will sometimes crash under normal use, is when you
have a lot of files in the Internet Explorer temporary files, and then
you clear the cache - this is too many IO events sometimes and a
"System.AccessViolationException" occurs.

Best I can think of is to allow the Framework to swallow the exception
again as in 1.1 by using this in the app.config, but it's a lousy hack:
<runtime>
<legacyUnhandledExceptionPolicy enabled="1" />
</runtime>

Any Ideas on how to make FileSystemWatcher more reliable? The example
code below is a simple console app, just paste and run...

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace TestConsole
{
class Program
{
private static FileSystemWatcher fsw;
private static int eventCount = 0;
private static string tempPath;

static void Main(string[] args)
{
tempPath =
System.Environment.GetEnvironmentVariable("TEMP").TrimEnd('\\');
Console.WriteLine("Press ENTER to begin...");
Console.ReadLine();
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Console.WriteLine(@"Creating/deleting files in temp dir.
Watch for results, then ENTER to exit...");
fsw = new FileSystemWatcher(tempPath);
fsw.EnableRaisingEvents = true;
fsw.Filter = "";
fsw.NotifyFilter = (NotifyFilters.Size |
NotifyFilters.FileName | NotifyFilters.DirectoryName);
fsw.InternalBufferSize *= 3;//default is 4096. Use a value
that won't overflow...
fsw.IncludeSubdirectories = true;
fsw.Error += new ErrorEventHandler(fsw_Error);
fsw.Changed += new FileSystemEventHandler(fsw_Changed);
fsw.Renamed += new RenamedEventHandler(fsw_Renamed);
fsw.Created += new FileSystemEventHandler(fsw_Created);
fsw.Deleted += new FileSystemEventHandler(fsw_Deleted);
for (int i = 0; i < 10; i++)
{
System.Threading.ThreadPool.QueueUserWorkItem(new
System.Threading.WaitCallback(startTest));
}
Console.ReadLine();
}

static void CurrentDomain_UnhandledException(object sender,
UnhandledExceptionEventArgs e)
{
Console.WriteLine("---------------------------------");
Console.WriteLine("An unhandled exception occurred: " +
((Exception)e.ExceptionObject).ToString());
}

static void fsw_Created(object sender, FileSystemEventArgs e)
{
System.Threading.Interlocked.Increment(ref eventCount);
}

static void fsw_Deleted(object sender, FileSystemEventArgs e)
{
System.Threading.Interlocked.Increment(ref eventCount);
}

static void fsw_Renamed(object sender, RenamedEventArgs e)
{
System.Threading.Interlocked.Increment(ref eventCount);
}

static void fsw_Changed(object sender, FileSystemEventArgs e)
{
System.Threading.Interlocked.Increment(ref eventCount);
}

static void fsw_Error(object sender, ErrorEventArgs e)
{
Console.WriteLine("FSW Error: " +
e.GetException().Message);
}

private static object _lock = new object();
private static void showEventCount()
{
lock (_lock)
{
int left = Console.CursorLeft;
int top = Console.CursorTop;
Console.Write("Event count: " + eventCount.ToString());
Console.SetCursorPosition(left, top);
}
}
private static void startTest(object o)
{
try
{
int x = 0;
for (int i = 0; i < 1000; i++)
{
string file = tempPath + @"\test_" +
Guid.NewGuid().ToString();
System.IO.File.Create(file).Close();
System.IO.File.Move(file, file + "r");
System.IO.File.Delete(file + "r");
x++;
if (x > 30)
{
showEventCount();
x = 0;
}
}
}
catch (System.Exception ex)
{
Console.WriteLine("Error during IO test: " +
ex.Message);
}
Console.WriteLine("Completed an IO test of multiple file
create/deletes.");
Console.WriteLine("Total of " + eventCount.ToString() + "
events fired.");
}
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top