2012-03-01 59 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; 
               })); 
    }