FileSystemWatcher Dispose调用挂起
我们刚开始遇到FileSystemWatcher的一个奇怪问题,其中对Dispose()的调用似乎已挂起。这段代码已经运行了一段时间,没有任何问题,但是我们刚刚升级到.NET3.5 SP1,因此我试图找出是否有人看到了此行为。这是创建FileSystemWatcher的代码:
if (this.fileWatcher == null) { this.fileWatcher = new FileSystemWatcher(); } this.fileWatcher.BeginInit(); this.fileWatcher.IncludeSubdirectories = true; this.fileWatcher.Path = project.Directory; this.fileWatcher.EnableRaisingEvents = true; this.fileWatcher.NotifyFilter = NotifyFilters.Attributes; this.fileWatcher.Changed += delegate(object s, FileSystemEventArgs args) { FileWatcherFileChanged(args); }; this.fileWatcher.EndInit();
使用此方法的方式是更新TreeNode对象的状态图像(略微调整以删除特定于业务的信息):
private void FileWatcherFileChanged(FileSystemEventArgs args) { if (this.TreeView != null) { if (this.TreeView.InvokeRequired) { FileWatcherFileChangedCallback d = new FileWatcherFileChangedCallback(FileWatcherFileChanged); this.TreeView.Invoke(d, new object[] { args }); } else { switch (args.ChangeType) { case WatcherChangeTypes.Changed: if (String.CompareOrdinal(this.project.FullName, args.FullPath) == 0) { this.StateImageKey = GetStateImageKey(); } else { projectItemTreeNode.StateImageKey = GetStateImageKey(); } break; } } } }
是我们缺少的东西,还是.NET3.5 SP1的一个奇特之处?
解决方案
回答
只是一个想法...这里是否有死锁问题?
我们正在调用TreeView.Invoke,这是一个阻塞调用。如果在单击任何按钮导致FileSystemWatcher.Dispose()调用时发生文件系统更改,则将在后台线程上调用FileWatcherFileChanged方法并调用TreeView.Invoke,该方法将阻塞,直到表单线程可以处理Invoke请求为止。但是,表单线程将调用FileSystemWatcher.Dispose(),直到处理完所有待处理的更改请求后,该线程才可能返回。
尝试将.Invoke更改为.BeginInvoke,看看是否有帮助。这可能会指出正确的方向。
当然,这也可能是.NET 3.5SP1问题。我只是根据我们提供的代码在这里推测。
回答
我们也有这个问题。我们的应用程序在.Net 2.0上运行,但由VS 2008 SP1编译。我也安装了.NET 3.5 SP1. 我也不知道为什么会发生这种情况,因为我们目前还没有其他线程在运行(这是在应用程序关闭期间),所以这看起来不像是一个死锁问题。
回答
斯科特,我们偶尔会看到control.Invoke在.NET 2中出现问题。尝试切换到control.BeginInvoke,看看是否有帮助。
这样做将允许FileSystemWatcher线程立即返回。我怀疑问题在某种程度上是control.invoke被阻止,从而导致FileSystemWatcher在处理时冻结。