2012-11-14 3 views
2

я следующие фрагменты кода:C# консольное приложение многопоточности вопрос с задачами

lock (lockObject) 
{ 
    foreach (KeyValuePair<string, List<string>> entry in productDictionary) 
    { 
    string writePath = String.Format(@"{0}\{1}-{2}.txt", directoryPath, hour,entry.Key); 
    Task writeFileTask = Task.Factory.StartNew(() => WriteProductFile(writePath, entry.Value)); 
    } 
} 

productDictionary является ConcurrentDictionary из <string, List<string>>, который я пытаюсь перебирать. Для каждой пары значений ключа я пытаюсь построить путь к файлу на основе Key, а затем выписать список строк, хранящихся в Value. Для этого я начинаю новую задачу, которая вызывает следующий метод:

public static void WriteProductFile(string filePath, List<string> productQuotes) 
{ 
    using(StreamWriter streamWriter = new StreamWriter(filePath)) 
    { 
     productQuotes.ForEach(x => streamWriter.WriteLine(x)); 
    } 
} 

Stepping через код все выглядит нормально на первый. Помещение точки останова при вызове метода для WriteProductFile показывает, что правильные параметры передаются в метод через Задачу. Однако, когда моя программа фактически сводит ее к методу WriteProductFile, параметры становятся несогласованными. То есть, список строк, которые не соответствуют пути к файлу, был передан, и поэтому мои данные не подходят после завершения программы. Ошибок не возникает, и программа выполняется нормально, но неправильная информация записывается в неправильные файлы.

Я думал, что ConcurrentDictionary и Lock позаботятся о любых проблемах с нитями, которые возникнут, но, видимо, я что-то пропустил. Есть идеи?

+0

Это немного запутанно ... «WriteProductFile» - это статический метод, что означает, что он совместно используется для одновременного выполнения задач ... – McGarnagle

+0

@dbaseman Я новичок в C# threading - это способ обойти это в статическом консольном приложении? –

ответ

3

Вы записываете переменную цикла. Вы должны объявить локальный внутри цикла.

foreach (KeyValuePair<string, List<string>> entry in productDictionary) 
{ 
    string writePath = String.Format(@"{0}\{1}-{2}.txt", directoryPath, hour, entry.Key); 
    List<string> list = entry.Value; // must add this. 
    Task writeFileTask = Task.Factory.StartNew(() => WriteProductFile(writePath, list)); 
} 

До C# 5 для всех итераций цикла используется одна переменная цикла. Каждое замыкание ссылается на одну и ту же переменную, и поэтому значение обновляется при запуске нового цикла цикла. Для окончательного объяснения вам следует прочитать сообщение Эрика Липперта: Closing over the loop variable considered harmfuil.

+0

Спасибо, похоже, сейчас работает нормально. Должен был увидеть это сам: P, но спасибо за помощь и отличную ссылку на статью –

Смежные вопросы