2013-10-30 86 views
1

我正在使用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方法解析。在這一刻,我可能會上傳兩次相同的文件,或者當我試圖從磁盤上刪除它時,我會得到一個異常,因爲它已被刪除。

    我可以看到更多的競爭條件與此代碼的情況。

任何想法如何我可以解決這個問題?

感謝

+1

如果這是所有相同的過程,爲什麼你不能同步這兩種方法? – devshorts

+0

您可以指定哪些條件觸發FileSystemWatcher,並刪除重命名文件時激活的觸發器。 – JConstantine

回答

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); 
} 
+0

我喜歡你的方法+1謝謝 –

1

我建議建立一個隊列和存儲文件上傳爲某種工作到隊列中。如果您處理隊列中的項目,您可以在嘗試上載之前檢查每個文件的存在情況。