1

我正在使用 aSystem.IO.FileSystemWatcher 来获得有关目录内文件重命名的通知。这些文件是日志文件,由不同的进程创建。

事件处理程序如下所示:

      private async void FileRenamedHandler(object sender, RenamedEventArgs e)
      {
          //when file is renamed
          //try to upload it to a storage
          //if upload is succesful delete it from disk 
      }

到目前为止一切看起来都很好,但是我需要添加第二种方法,该方法在此应用程序启动时遍历目录,以便将现有日志文件上传到存储

所以

    public async Task UploadAllFilesInDirectory()
    {
        foreach (var file in Directory.GetFiles(_directoryPath))
        {
          await TryUploadLogAsync(file);
        }
    }

问题是我进入了竞争条件,例如:

  • 文件刚刚被重命名并且 FileRenamedHandler 被触发,但同样的填充也会被UploadAllFilesInDirectory方法解析。在这一刻,我可能会两次上传同一个文件,否则在尝试从磁盘中删除它时会出现异常,因为它已经被删除了。

    我可以使用此代码查看更多竞争条件案例。

知道我该如何解决这个问题吗?

谢谢

4

2 回答 2

2

您可以使用 aConcurrentDictionary来跟踪当前正在处理的项目,并让它担心线程安全。

创建字典,其中键是文件路径(或其他标识对象),值是……随便。我们将其视为一个集合,而不是字典,但没有ConcurrentSet,因此必须这样做。

然后对于每个文件,您必须处理 call TryAdd。如果它返回 true,则您添加了对象,您可以处理该文件。如果它返回 false,那么文件就在那里,并且正在其他地方处理。

然后,您可以在完成处理后删除该对象:

//store this somewhere
var dic = new ConcurrentDictionary<string, string>();

//to process each file
if (dic.TryAdd(path, path))
{
    //process the file at "path"
    dic.TryRemove(path, out path);
}
于 2013-10-30T17:37:30.157 回答
1

我建议建立一个队列并将要上传的文件作为某种作业存储到队列中。如果您处理队列中的项目,您可以在尝试上传之前检查每个文件是否存在。

于 2013-10-30T17:54:26.793 回答