ThreadPool QueueUserWorkItem со списком

Я хотел бы использовать QueueUserWorkItem из ThreadPool. Когда я использую следующий код, все работает хорошо.

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

Что я не прав? Что я должен изменить?

Обновить

Извините, я ошибся в коде. Я использую.NET 2.0 с VS2010. Вот полный код:

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

Спасибо

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.

Как указал Ганс, неясно, откуда происходит "я". Но я также вижу, что ваш блок утилизации выходит и удаляется, потому что вы не используете на нем WaitOne (или вы не скопировали эту часть кода).

Также я бы предпочел использовать WaitAll и не использовать блокировку.

Другие вопросы по тегам