我正在使用System.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
方法解析。在这一刻,我可能会上传相同的文件两次,或者在尝试从磁盘中删除它时会出现异常,因为它已被删除。
我可以通过此代码查看更多竞争条件案例。
知道如何解决这个问题吗?
谢谢
答案 0 :(得分:2)
您可以使用ConcurrentDictionary
来跟踪当前正在处理的项目,并让它担心线程安全。
创建字典,其中键是文件路径(或其他一些标识对象),值是......无论如何。我们将此视为一个集合,而不是字典,但没有ConcurrentSet
,因此必须这样做。
然后,对于每个文件,您必须处理呼叫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);
}
答案 1 :(得分:1)
我建议构建一个队列,并将要上传的文件存储为队列中的某种作业。如果您处理队列中的项目,则可以在尝试上传之前检查每个文件是否存在。