简体   繁体   English

在C#中实现以下长时间运行的线程的更好方法

[英]Better way to implement the following long running thread in C#

I have an application that has a main thread that waits for an event (receiving a file in the directory, for example) and Post that file to an API. 我有一个具有主线程的应用程序,该主线程等待事件(例如,接收目录中的文件)并将该文件发布到API。 This part is working fine. 这部分工作正常。

On the other hand, due to some reasons, it's possible that the main thread misses out some files. 另一方面,由于某些原因,主线程可能会丢失某些文件。 So, I have setup a background thread to run throughout application lifetime cleaning up those missed files as shown below: 因此,我设置了一个后台线程以在应用程序的整个生命周期中运行,以清除那些丢失的文件,如下所示:

public virtual void MissedFileHandler()
{
     if (_missedFileHandlerThread == null || !_missedFileHandlerThread.IsAlive)
     {
          _missedFileHandlerThread = new Thread(new ThreadStart(ClearMissedFiles));
          _missedFileHandlerThread.IsBackground = true;
          _missedFileHandlerThread.Start();
     }
}

protected virtual void ClearMissedFiles()
{
     while (true)
     {
         string[] missedFiles = new string[] { };
         missedFiles = Directory.GetFiles(ConfigurationHelper.applicationRootDirectory, "*.txt", SearchOption.TopDirectoryOnly);
         Parallel.ForEach(missedFiless, (currentMissedFile) =>
         {
             bool isFileInUse = true;
             isFileInUse = FileHelper.CheckIfFileInUse(filesInUseCollection, currentMissedFile)
             if (!isFileInUse)
             {
                 bool isHttpTransferSuccess = false;
                 isHttpTransferSuccess = FileHelper.SendFileToApi(userid, currentMissedFile);
             if (isHttpTransferSuccess)
             {
                  File.Delete(currentMissedFile);

             }
         }
     });
     Thread.Sleep(1000);
     }
  }

Please note that running this as a Windows service or a scheduler is not an option for some other reasons. 请注意,由于某些其他原因,不能将其作为Windows服务或调度程序运行。 So, I do need a background worker to clean up missed files periodically. 因此,我确实需要后台工作人员定期清理丢失的文件。 I checked out Timer and WaitHandles but not very sure how I can implement the following using those. 我签出了TimerWaitHandles但不太确定如何使用它们实现以下功能。

The way the two processes (main even handler for new files and the background cleaner is invoked are, in the main application thread I will instantiate the class and invoke the methods at application startup. It's the Thread.Sleep() and the while (true) that is bothering me and am looking for a better approach. Thanks. 在主应用程序线程中,我将实例化该类并在应用程序启动时调用方法,这两个过程(新文件的主偶处理程序和后台清理程序的调用方式Thread.Sleep()Thread.Sleep()while (true) ,这困扰着我,并且正在寻找更好的方法。谢谢。

You can use a file watcher to detect new files in that directory. 您可以使用文件监视程序来检测该目录中的新文件。

private void watch()
{
  FileSystemWatcher watcher = new FileSystemWatcher();

  // Set your path with this
  watcher.Path = path;

  // Subscribe to event
  watcher.Changed += new FileSystemEventHandler(OnChanged);
  watcher.EnableRaisingEvents = true;
}

Try using Microsoft's Reactive Framework. 尝试使用Microsoft的Reactive Framework。 Then you can do this: 然后,您可以执行以下操作:

IObservable<Unit> fileChanges =
    Observable
        .Using(() =>
        {
            var fsw = new FileSystemWatcher();
            fsw.Path = path;
            fsw.EnableRaisingEvents = true;
            return fsw;
        }, fsw =>
            Observable
                .FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
                    h => fsw.Changed += h,
                    h => fsw.Changed -= h))
        .Select(ep => Unit.Default);

IObservable<Unit> periodically =
    Observable
        .Interval(TimeSpan.FromSeconds(30.0))
        .Select(x => Unit.Default);

IObservable<string> clearMissedFiles =
    fileChanges
        .Merge(periodically)
        .SelectMany(u => Directory.GetFiles(ConfigurationHelper.applicationRootDirectory, "*.txt", SearchOption.TopDirectoryOnly))
        .Where(f => !FileHelper.CheckIfFileInUse(filesInUseCollection, f))
        .SelectMany(f => Observable.Start(() => FileHelper.SendFileToApi(userid, f)), (f, s) => new { file = f, success = s })
        .Where(x => x.success)
        .Select(x => x.file);

IDisposable subscription =
    clearMissedFiles
        .Subscribe(f => File.Delete(f));

This watches the file system and check periodically. 这会监视文件系统并定期检查。 And calls the API in parallel and it doesn't cause the O/S grief with trying to delete multiple files at once. 并以并行方式调用该API,并且不会因尝试一次删除多个文件而导致操作系统痛苦。

Just call subscription.Dispose() to clean up before exiting. 只需在退出之前调用subscription.Dispose()进行清理即可。

NuGet "System.Reactive" for the bits and then reference using System.Reactive.Linq for the extensions to show. NuGet“ System.Reactive”为位,然后using System.Reactive.Linq引用以显示扩展名。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM