尽管线程同步C#

时间:2017-12-22 02:58:54

标签: c# multithreading locking ioexception

我已经在同一个类中设置了2个事件处理程序(让我们称之为WrapperClass):一个用于将文件保存到文件夹,另一个用于将这些文件发送到web api。在应用程序主线程中,我在应用程序启动时调用了两个方法:

// save file to folder:
NewFileEventHandler();
// send file to api:
FileTransporter();

NewFileEventHandler的定义如下:

public void NewFileEventHandler()
{
    SomeEventClass.NewFileEvent +=
         new FileEventHandler(SaveFileToFolder);
}

private void SaveFileToFolder(File file)
{
    FileHelper.SaveFileToFolder(file);
}

FileTransporter定义如下,这是我遇到问题的地方:

public void FileTransporter()
{
     FileSystemWatcher newFileWatcher = new FileSystemWatcher();
     newFileWatcher.Path = ConfigurationHelper.applicationRootDirectory;
     newFileWatcher.Filter = "*.txt";
     newFileWatcher.Created +=
     new FileSystemEventHandler(TransportFile);
     newFileWatcher.EnableRaisingEvents = true;
}

And the `TransportFile()` is given below:

private void TransportFile(object source, FileSystemEventArgs e)
{
    lock (_fileTransportLock)
    {
         string[] files = new string[] { };
         files = Directory.GetFiles(ConfigurationHelper.applicationRootDirectory, "*.txt", SearchOption.TopDirectoryOnly);
         Parallel.ForEach(files, (currentFile) =>
         {
             bool isHttpTransferSuccess = false;

             isHttpTransferSuccess = FileHelper.SendFileToApi(userid, currentFile);
             if (isHttpTransferSuccess)
             {
                 File.Delete(currentFile);
             }
        });
     }
}

但是,行:

抛出异常:

System.IO.IOException: The process cannot access the file 'C:\Users\myapp\file.txt' because it is being used by another process.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at System.IO.File.Open(String path, FileMode mode)
   at FileHelper.SendFileToApi(String userId, String fileLocation)

我不明白的是,因为lock唯一可能使用此文件的两个进程是保存文件的线程和尝试将文件发送到的文件的线程API。但是,我对FileSystemWatcher.Created事件的理解是它在文件创建完成时触发。这意味着,保存文件的线程不应该在TransportFile()方法尝试打开文件以将其发送到api时使用该文件。

有时文件夹中有多个文件(由于过去错过了电子邮件)。 IOException仅针对刚刚保存到文件夹的文件(换句话说,引发FileSystemWatcher.Created事件的文件抛出。文件夹中的其他文件按预期清除。任何人都可以帮助请谢谢。

1 个答案:

答案 0 :(得分:3)

这里有一些你不想要的东西:

  1. 您要挂钩的事件是FileCreated。当该文件由其他进程创建时, not 当其他进程完成文件写入时,会触发此事件(可能不足为奇)。这里发生的是,当其他进程仍在编写文件时,您的进程会收到通知,并且对其进行独占锁定。来自the documentation
  2.   

    创建文件后立即引发OnCreated事件。如果是文件   被复制或转移到一个观察目录,OnCreated   将立即引发事件,然后是一个或多个OnChanged   事件

    1. 创建文件后,循环遍历目录中的所有文件(不仅仅是刚刚创建的文件)并传输所有文件。如果创建了多个文件,则对事件的第一次调用将尝试访问目录中的任何文件(实际上是并行),因此即使1)不是问题,您可能会在此处发生冲突处理第一个事件时写入的另一个文件。
    2. 这里要做的就是循环,直到你能够阅读文件,如第二个答案中所述:Wait for file to be freed by process