C# 如何同步处理filesystemwatcher事件?

C# 如何同步处理filesystemwatcher事件?,c#,.net,multithreading,locking,filesystemwatcher,C#,.net,Multithreading,Locking,Filesystemwatcher,我有以下同步问题 线程在循环中运行,如果它在文件系统中检测到一个尚未处理的文件夹(可能是在应用程序未运行时添加的),则该文件夹将通过Process方法作为新文件夹处理: void Loop() { while (run) { lock(renameLock) { var newFolders = EnumerateNewFolders().ExceptThoseMarkedAsRenamed(); Process(newFolders); MarkAsProc

我有以下同步问题

线程在循环中运行,如果它在文件系统中检测到一个尚未处理的文件夹(可能是在应用程序未运行时添加的),则该文件夹将通过
Process
方法作为新文件夹处理:

void Loop()
{
 while (run)
 {
  lock(renameLock)
  {
    var newFolders = EnumerateNewFolders().ExceptThoseMarkedAsRenamed();
    Process(newFolders);
    MarkAsProcessed(newFolders);
  }
  Sleep();
 }
}
重命名的文件夹不应作为新文件夹处理,而应作为重命名文件夹处理,并标记为重命名文件夹,以便以后不再作为新文件夹处理

为了解决这个问题,我有一个
FileSystemWatcher
和一个
重命名事件的处理程序:

private void fsw_Renamed(object sender, RenamedEventArgs e)
{
  lock(renameLock)
  {
    ProcessRename(e);
    //mark folder as renamed so that ExceptThoseMarkedAsRenamed filters it out
    MarkAsRenamed(e);
  }
}
通常情况下,当执行重命名时,文件夹首先在
fsw_rename
中标记为重命名,然后在循环中由
过滤掉,但标记为重命名的文件夹除外
,并且不作为新文件夹处理

但有时会出现以下顺序:

  • 在Windows资源管理器和文件系统中重命名文件夹(循环处于锁定状态时)
  • 发生fsw_重命名,但无法获取锁
  • 循环线程仍保持锁定,并将文件夹作为新文件夹拾取(它尚未标记为重命名)
  • 循环线程释放锁
  • 发生重命名事件,获取锁,并将文件夹标记为重命名。但已经太晚了,因为它已经作为新的处理
  • 我很难弄清楚如何确保重命名的文件夹永远不会作为新文件夹处理

    重命名文件夹是指已发生或将在不久的将来发生重命名事件的文件夹,因为文件系统更改和重命名事件之间存在固有的延迟(并且文件系统中的实际更改和引发的事件不是原子的)


    如何确保循环始终考虑重命名的fsw_所做的更改,即使事件发生在循环保持锁定的过程中?

    您希望处理文件夹,根据文件夹是新文件夹还是简单重命名文件夹,进行两种不同的处理。 您正在使用fs监视对象,该对象在重命名给定文件夹时触发事件。 您应该对新文件夹使用类似的监视,并让这些事件创建绑定到该文件夹的任务

    捕获事件的线程不会有争用条件问题,只会分派新任务,因此它不会被处理延迟,并且能够在新事件发生时处理它们。 任务队列可以是包含文件夹和要应用于它的任务的对的列表

    当计划处理文件夹时,监视器应通过检查任务队列以查看文件夹是否存在,过滤掉发生在文件夹上的任何事件。它甚至可以根据其他因素更改任务或将其删除(例如,如果文件夹在处理之前已被删除,那么也可以监视该事件)

    任务可能类似于:

    • 锁定要处理的文件夹(这样可以避免对文件夹的外部影响)
    • 处理它
    • 将其标记为“已处理”(从列表中删除)
    • 打开它
    您不能保留renameLock,因为它首先会造成问题。 如果无法锁定文件夹,也许可以将其移动到其他地方(我想这在技术上类似于重命名)进行处理,然后将其移回原位


    这解决了在C#中锁定文件夹的问题。

    您可以尝试以下方法:

  • 仅在应用程序启动时运行
    循环
    方法。可能在订阅
    FileSystemWatcher
    之前
  • 订阅
    FileSystemWatcher。在订阅
    FileSystemWatcher.rename的目录上创建
  • 保持
    FileSystemWatcher。按原样重命名订阅
  • 移除锁,因为这两个事件不应该相互冲突
  • 第一步。将处理在应用程序未运行时创建/重命名的目录

    第二步。将在应用程序运行时处理新目录


    第三步。将在应用程序运行时处理重命名的目录。

    我看不到所有其他代码,但从一开始,这看起来不是一种非常有效的解决方案。看起来您将面临巨大的锁争用。您是否能够向第一个线程发出处理更改的“信号”(而不是sleep())?我可能根本不知道你为什么要循环。我发布的代码是一个高度简化的示例,我对锁争用有任何问题都很感兴趣。循环中没有真正的睡眠。你也不是在回答我的问题,只是在评论一个无关的问题。我之所以循环,是因为我需要检测新文件夹,并且我还需要处理FSW未处理的文件夹(例如,当应用程序未运行或处于挂起状态时)。这将不起作用。问题是,在我设法“锁定要处理的文件夹”之前,循环已经在处理它了。我要解决的问题是如何处理文件系统更改和FSW重命名事件之间的延迟—有时循环直接跳转到延迟中。我完全重新设计了我的答案。事实上,我一开始并不理解这个问题。感谢您抽出时间回来重新设计答案!在我的例子中,锁定文件夹是不可行的,但是事件驱动的任务方法可能会起作用。关键是删除循环并更多地依赖于创建的事件,尽管我不太信任FSW,而仅仅依赖它。如果你不信任FSW类(事实上,它的可靠性似乎充满了问题),也许你可以基于更多的基础系统调用实现一个。我没有这样做的经验,所以我不能谈论这样做的可行性