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 и не использовать блокировку.