FileSystemWatcher Dispose 调用挂起
-
09-06-2019 - |
题
我们刚刚开始遇到 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问题。我只是根据您提供的代码在这里推测。
其他提示
Scott,我们偶尔会在 .NET 2 中看到 control.Invoke 的问题。尝试切换到 control.BeginInvoke 并查看是否有帮助。
这样做将允许 FileSystemWatcher 线程立即返回。我怀疑您的问题是 control.Invoke 阻塞,从而导致 FileSystemWatcher 在处置时冻结。
我们也遇到这个问题。我们的应用程序在.Net 2.0 上运行,但由 VS 2008 SP1 编译。我也安装了.NET 3.5 SP1。我也不知道为什么会发生这种情况,它看起来不像我们这边的死锁问题,因为此时没有其他线程正在运行(它是在应用程序关闭期间)。