我遇到以下同步问题。
一个线程在一个循环中运行,如果它检测到文件系统中尚未处理的文件夹(它可能是在应用程序未运行时添加的),则Process
将该文件夹作为新文件夹处理方法:
void Loop()
{
while (run)
{
lock(renameLock)
{
var newFolders = EnumerateNewFolders().ExceptThoseMarkedAsRenamed();
Process(newFolders);
MarkAsProcessed(newFolders);
}
Sleep();
}
}
重命名的文件夹不应该作为新文件处理,而是作为重命名处理并标记为重命名,以便以后不再处理它们。
为了解决这个问题,我有一个FileSystemWatcher
和Renamed
事件的处理程序:
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_Renamed
中标记为重命名,然后在ExceptThoseMarkedAsRenamed
循环过滤掉,而不是新处理。
但有时会出现以下顺序:
我无法确定如何确保重命名的文件夹永远不会被处理为新文件夹。
重命名的文件夹是Renamed
事件发生或将在近期发生的文件夹,因为文件系统更改与FileSystemWatcher.Renamed
事件之间存在固有延迟(并且文件系统和引发的事件的实际更改不是原子的。)
如何确保循环始终考虑fsw_Renamed完成的更改,即使Loop在持锁时发生了事件?
答案 0 :(得分:1)
您希望根据文件夹是新文件夹还是仅重命名文件来处理文件夹,并进行两种不同的处理。 您正在使用fs监视对象,该对象在重命名给定文件夹时触发事件。 您应该对新文件夹使用类似的监视,并让这些事件创建绑定到该文件夹的任务。
捕获事件的线程不会出现竞争条件问题,并且只会调度新任务,因此不会因处理而延迟,并且能够在事件发生时处理新事件。 任务队列可以只是包含文件夹和要应用于其的任务的对列表。
当计划文件夹进行处理时,监视器应过滤掉发生在它们上的任何事件,方法是检查任务队列以查看该文件夹是否存在。它甚至可以根据其他因素更改任务或删除它(如果文件夹在被处理之前已被删除 - 也许监视该事件也是好的。)
任务可能类似于:
你不能保留renameLock,因为它首先是创建问题的东西。 如果你无法锁定文件夹,也许你可以在其他地方移动它(它在技术上就像重命名一样)进行处理,然后将其移回原位。
此SO question处理在C#中锁定文件夹的问题。
答案 1 :(得分:1)
您可以尝试以下方法:
Loop
方法 。可能在订阅FileSystemWatcher
之前。FileSystemWatcher.Created
目录的FileSystemWatcher.Renamed
。FileSystemWatcher.Renamed
订阅原样。步骤1.将处理在您的应用程序未运行时创建/重命名的目录。
步骤2.将在您的应用程序 正在运行时处理新目录。
步骤3.将在您的应用程序 正在运行时处理重命名的目录。