后台工作进程和文件系统观察程序一起工作时出错

本文关键字:工作 一起 出错 程序 文件系统 进程 后台 观察 | 更新日期: 2023-09-27 18:26:26

嗨,我在使用Filesystemwatch&BackgroundWorker进程。

我有一个windows窗体应用程序,它检查文件夹中的新文本文件,处理它们并从中创建xml文件。

我正在使用FSW监控文件夹中的新txt文件,该应用程序运行良好,但当文件夹接收到大量文件(比如1000个)时,该应用会冻结,因为它正在处理所有文件。

我突然想到添加一个后台工作程序,所以FSW每次创建新文件时都会调用它,这样我们就可以在后台处理文件,而不会冻结UI。

这个想法没有奏效,因为对于创建的每个文件,我都会尝试调用RunWorkerSync()方法,所以如果它忙于处理一个文件,而我试图处理一个新文件,它会抛出以下错误:

"此BackgroundWorker当前正忙,无法同时运行多个任务。"

所以我试着循环这个方法一段时间,直到它可用,但是,抛出了无限的异常。这是我的代码的简化版本:

private void fileSystemWatcher1_Created(object sender, System.IO.FileSystemEventArgs e)
    {
        readFile();
    }
    private void readFile()
    {
        while (backgroundWorker1.IsBusy)
        {
            readFile();
        }
        backgroundWorker1.RunWorkerAsync(idx);
    }
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        int i = (int)e.Argument;
        i += 1;
        e.Result = i;
    }
    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        label1.Text = "Processing...";
        this.Refresh();
    }
    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        label1.Text = "Completed...";
        this.Refresh();
        idx = (int)e.Result;
    }

抛出的异常显示"WindowsFormsApplication2.exe中发生类型为"System.StackOverflowException"的未处理异常,请确保没有无限循环或递归"

我当然可以删除FSW,但我想知道是否有办法让它们协同工作,有什么想法吗?

后台工作进程和文件系统观察程序一起工作时出错

您遇到的是一个典型的生产者/消费者问题。

System.Collections.Concurrent.ConcurrentQueue<string>求解。

  • 在FSW事件中,将文件名添加到队列中
  • 启动1或2个BackgroundWorkers来处理队列

这是匆忙溢出堆栈的代码:

private void readFile()
{
    while (backgroundWorker1.IsBusy)
    {
        readFile();  // the recursive call, will fail quickly
    }
    backgroundWorker1.RunWorkerAsync(idx);
}

这不仅会导致SO异常,还会阻塞主线程
您需要一种更好的等待方式,ConcurrentQueue为您提供了这一点。

实例化新的BackgroundWorkers就可以了,就像Henk上面的解决方案一样。

或者,只需使用ThreadPool,就可以在不过多更改代码的情况下完成此操作。

    private void fileSystemWatcher1_Created(object sender, System.IO.FileSystemEventArgs e)
    {
        ThreadPool.QueueUserWorkItem(o => readFile(e));
    }

    public void readFile(System.IO.FileSystemEventArgs e)
    {
        this.BeginInvoke(new MethodInvoker(() =>
                                               {
                                                   label1.Text = "Processing...";
                                                   this.Refresh(); //you shouldn't need this
                                               }));
        //your long running read/processing... doing something event args
        this.BeginInvoke(new MethodInvoker(() =>
                                               {
                                                   label1.Text = "Completed...";
                                                   this.Refresh();
                                                   idx = (int) e.Result;
                                               }));
    }

为什么不在readFile中实例化一个新的BackgroundWorker而不是重用?