后台工作进程和filesystemwatcher错误一起工作

时间:2012-03-01 20:31:15

标签: c# .net winforms backgroundworker filesystemwatcher

您好我使用Filesystemwatcher& BackgroundWorker流程。

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

我正在使用FSW监视文件夹上的新txt文件,该应用程序工作正常,但当文件夹收到大量文件(假设为1000)时,应用程序冻结,因为它正在处理所有这些文件。

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

这个想法不起作用,因为对于每个创建的文件,我尝试调用RunWorkerAsync()方法,所以如果它忙于处理文件并且我尝试处理一个新文件,它将抛出以下错误:

“此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,但我想知道是否有办法让它们一起工作,有什么想法吗?

3 个答案:

答案 0 :(得分:2)

您拥有的是经典的制作人/消费者问题。

使用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会为您提供。

答案 1 :(得分:1)

实例化新的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;
                                               }));
    }

答案 2 :(得分:0)

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