Search code examples
.netthread-safetyfilesystemwatcher

Is using FileSystemWatchers sharing the same event handler safe?


Is using FileSystemWatchers sharing the same event handler safe?

Is it safe having multiple FileSystemWatchers watching different directories using the same event handler?

Class Snippets
    Private _watchPaths As New List(Of String) From {"x:\Dir1", "x:\Dir2"}
    Private _watchers As List(Of FileSystemWatcher)
    Private _newFiles As New BlockingCollection(Of String)

    Sub Watch()
        Dim _watchPaths As New List(Of String) From {"x:\Dir1", "x:\Dir2"}
        Dim watchers As List(Of FileSystemWatcher)

        For Each path In _watchPaths
            Dim watcher As New FileSystemWatcher
            AddHandler watcher.Created, Sub(s, e)
            _trace.DebugFormat("New file {0}", e.FullPath)
            'Do a little more stuff
            _newFiles.Add(e.FullPath)
            End Sub
        Next
    End Sub
End Class

Or must we wrap the FileSystemWatcher in a Class like the following to make the event handlers thread-safe?

Class FileWatcher
    Private _fileSystemWatcher As New FileSystemWatcher

    Public Sub Start(path As String, filter As String, action As Action(Of Object, FileSystemEventArgs))
        With _fileSystemWatcher
            .Path = path
            .Filter = filter
            .EnableRaisingEvents = True
            AddHandler .Created, Sub(s, e)
            action(s, e)
            End Sub
        End With
    End Sub

    Public Sub [Stop]()
        _fileSystemWatcher.Dispose()
    End Sub
End Class

Here the usage of the helper Class:

Sub Watch
    For Each path In _watchPaths
        Dim Watcher as new FileWatcher
        watcher.Start(path, "*.txt"), Sub(s, e)
        _trace.DebugFormat("New file {0}", e.FullPath)
        'Do a little more stuff
        _newFiles.Add(e.FullPath)
        End Sub)      
    Next
End Sub

Solution

  • Events raised by the FileSystemWatcher are, by default, raised on thread pool threads. Which means any data used within the event handler is "shared"--regardless of whether you have multiple handlers. You should guard (e.g. lock access) this shared data to avoid corruption.

    Alternatively, you can use FileSystemWatcher.SynchronizingObject to provide a synchronization context so that all events raised on a FileSystemWatcher occur on a single, or a known thread. This is typically done if your event handlers touch GUI elements.