2

サンプル プログラム: いくつかのフォルダーで FileSystem イベントをリッスンし、Timer イベントが発生したときに FileSystem イベント情報をコンソールに出力します。

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

List<string> listOfChanges両方のイベント ハンドラーから同じストレージ static にアクセスしても安全ですか? イベントが下でどのように機能するかがよくわかりません。グローバル イベント ハンドラー キューを作成し、イベントの種類に関係なく、すべてのイベント ハンドラーを 1 つずつ実行しますか? それとも、イベント ハンドラーの種類ごとに異なるスレッドを作成しますか?

編集:BlockingCollectionを使用する のが最善の解決策だと思いますConcurrentQueueので、次のようにする必要があります。

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

3 に答える 3

2

汎用リストはスレッドセーフではありません。listOfChangesが(OnTimerEpleasedで)トラバースされるとエラーが発生する可能性があり、新しいエントリによってリストにエントリが追加されます(OnFileCreatedOrDeleted)。http://msdn.microsoft.com/en-us/library/6sh2ey19.aspxを参照してください。リストへのアクセスを同期するか、組み込みのスレッドセーフコレクションを使用します:http://msdn.microsoft.com/en-us/library/system.collections.concurrent.aspx

于 2012-12-06T08:50:12.553 に答える
0

FileSystemWatcher が複数のスレッドを使用しているかどうかはわかりませんが、安全のためにリストへのアクセスを

lock (listOfChanges)
{
    //Code that reads or writes to the listOfChanges.
}
于 2012-12-06T08:59:40.830 に答える
0

これらのイベント ハンドラーが単一のスレッドから呼び出されると想定しないでください。FileSystemWatcher も Timer のドキュメントにも、これらのハンドラーがどのように呼び出されるかについては言及されていないため、ここでは安全な方法を選択し、このリストへのアクセスが同期されていることを確認します。

于 2012-12-06T08:59:56.800 に答える