Щях да публикувам въпрос, но го разбрах преди време и реших да публикувам въпроса и отговора - или поне моите наблюдения.
Когато използвате анонимен делегат като WaitCallback, където ThreadPool.QueueUserWorkItem се извиква в foreach цикъл, изглежда, че една и съща foreach-стойност се предава във всяка нишка.
List< Thing > things = MyDb.GetTheThings();
foreach( Thing t in Things)
{
localLogger.DebugFormat( "About to queue thing [{0}].", t.Id );
ThreadPool.QueueUserWorkItem(
delegate()
{
try
{
WorkWithOneThing( t );
}
finally
{
Cleanup();
localLogger.DebugFormat("Thing [{0}] has been queued and run by the delegate.", t.Id );
}
});
}
За колекция от 16 екземпляра на Thing в Things наблюдавах, че всяко „Thing“, предадено на WorkWithOneThing, съответства на последния елемент в списъка „things“.
Подозирам, че това е така, защото делегатът осъществява достъп до външната променлива „t“. Обърнете внимание, че също експериментирах с предаването на Thing като параметър на анонимния делегат, но поведението остана неправилно.
Когато префакторирах кода, за да използвам именуван метод WaitCallback и предадох Thing 't' на метода, voilà ... i-тото копие на Things беше правилно предадено в WorkWithOneThing.
Урок по паралелизъм, предполагам. Предполагам също, че семейството Parallel.For се занимава с това, но тази библиотека не беше опция за нас в този момент.
Надявам се това да спести време на някой друг.
Хауърд Хофман