2012-03-01 60 views
1

嗨我有一个问题,使用Filesystemwatcher & BackgroundWorker进程。后台工作进程和filesystemwatcher错误一起工作

我有一个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; 
    } 

引发的异常说“类型‘System.StackOverflowException’未处理的异常发生在WindowsFormsApplication2.exe,确保你没有一个无限循环或递归”

当然,我可以删除FSW,但我想知道是否有办法让他们一起工作,有什么想法?

+1

你可以发布堆栈跟踪吗? – cadrell0 2012-03-01 20:35:04

回答

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会给您提供。

0

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

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