2010-09-15 90 views
1

我想從ThreadPool中使用QueueUserWorkItem。當我使用下面的代碼時,一切正常。ThreadPool QueueUserWorkItem with list

private int ThreadCountSemaphore = 0; 
private void (...) { 

var reportingDataList = new List<LBReportingData>(); 
ThreadCountSemaphore = reportingDataList.Count; 
using (var autoResetEvent = new AutoResetEvent(false)) { 
    ThreadPool.QueueUserWorkItem((o) => this.FillReportingData(settings, reportingDataList[0], autoResetEvent)); 
    ThreadPool.QueueUserWorkItem((o) => this.FillReportingData(settings, reportingDataList[1], autoResetEvent)); 
    ThreadPool.QueueUserWorkItem((o) => this.FillReportingData(settings, reportingDataList[2], autoResetEvent)); 
} 
} 

private void FillReportingData(...) { 
if (Interlocked.Decrement(ref this.ThreadCountSemaphore) == 0) { 
       waitHandle.Set(); 
       } 
} 

但是,當我使用列表而不是單個方法調用,然後我的程序崩潰沒有例外。

private void (...) { 

var reportingDataList = new List<LBReportingData>(); 
ThreadCountSemaphore = reportingDataList.Count; 
using (var autoResetEvent = new AutoResetEvent(false)) { 
    ThreadPool.QueueUserWorkItem((o) => this.FillReportingData(settings, reportingDataList[i], autoResetEvent)); 
} 
} 

我錯了什麼?我應該改變什麼?

更新

對不起,我做了在代碼中的錯誤。我在VS2010中使用.NET 2.0。 下面是完整的代碼:

private int ThreadCountSemaphore = 0; 

     private IList<LBReportingData> LoadReportsForBatch() { 
      var reportingDataList = new List<LBReportingData>(); 
      var settings = OnNeedEntitySettings(); 

      if (settings.Settings.ReportDefinition != null) { 
       var definitionList = new List<ReportDefinitionen> { ReportDefinitionen.OrgStatus, ReportDefinitionen.Mittelwerte, ReportDefinitionen.Verteilungsstatistik }; 
       using (var autoResetEvent = new AutoResetEvent(false)) { 
        foreach (var reportDefinition in definitionList) { 
         foreach (DataRow row in settings.Settings.ReportDefinition.Select("AuswertungsTyp = " + (int)reportDefinition)) { 
          reportingDataList.Add(new LBReportingData { SourceData = row, ReportType = reportDefinition }); 
         } 
        } 

        ThreadCountSemaphore = reportingDataList.Count; 

        foreach(var reportingDataItem in reportingDataList) {          
         ThreadPool.QueueUserWorkItem((o) => this.FillReportingData(settings, reportingDataItem, autoResetEvent)); 
        } 
        autoResetEvent.WaitOne(); 
       } 
      } 
      return reportingDataList; 
     } 

private void FillReportingData(IEntitySettings<DSLBUReportDefinition> settings, LBReportingData reportingData, AutoResetEvent waitHandle){ 

      DoSomeWork(); 
      if (Interlocked.Decrement(ref this.ThreadCountSemaphore) == 0) { 
       waitHandle.Set(); 
      } 
     } 

感謝

+1

非常不清楚,「我」的價值應該從哪裏來? – 2010-09-15 17:29:27

+0

如果這是C#,則省略號不是允許的參數。因此,爲了更好地解決此問題,我們需要知道您爲'FillReportingData'聲明的參數類型。另外,在示例2中,您仍然只傳遞一個「LBReportingData」對象,而不是整個列表。 – 2010-09-15 17:31:21

回答

0

正如漢斯指出,目前尚不清楚其中「i」是從哪裏來的。但是我也可以看到你的配置塊出去了,因爲你沒有使用WaitOne(或者你沒有複製那部分代碼)。

另外我寧願使用WaitAll而不使用互鎖。

+0

在這種特殊情況下'WaitAll'會很好,但是它在高容量時確實存在限制。 – James 2010-09-15 17:46:43

2

您在排隊工作項目後立即處置WaitHandle。主線程中的Dispose和工作線程中的Set之間存在競爭。可能還有其他問題,但由於代碼不完整,難以猜測。

下面是該模式如何工作。

using (var finished = new CountdownEvent(1)) 
{ 
    foreach (var item in reportingDataList) 
    { 
    var captured = item; 
    finished.AddCount(); 
    ThreadPool.QueueUserWorkItem(
     (state) => 
     { 
     try 
     { 
      DoSomeWork(captured); // FillReportingData? 
     } 
     finally 
     { 
      finished.Signal(); 
     } 
     }, null); 
    } 
    finished.Signal(); 
    finished.Wait(); 
} 

該代碼使用CountdownEvent類。它可用於.NET 4.0或作爲Reactive Extensions下載的一部分。

+0

+1處理AutoResetEvent是我看到的第一個紅旗,但是,如果沒有完整的代碼,很難準確定位它,但我堅決認爲這是整體問題的一部分。 – James 2010-09-15 18:06:51