2016-01-24 6 views
1

Я создал структуру, скажем AStruct, и переопределяет ее метод ToString(). Тогда я написал параллель, чтобы вернуть некоторые AStruct и поместить их в список, так что я могу использовать StreamWriter выводить их, какБезопасность потоков StringBuilder в Parallel.For

StreamWriter sw = new StreamWriter(@"ABC.txt"); 
StringBuilder sb = new StringBuilder(); 
List<AStruct> AList = new List<AStruct>(); 

Parallel.For(0,10,i =>       // generate 10 AStruct(s) 
{ 
    AList.Add(DoSomethingThatReturnsAStruct); 
}); 

for(int i =0; i< AList.Count();i++)    //put in a StringBuilder 
{ 
    sb.AppendLine(AList[i].ToString()); 
} 
sw.Write(sb.ToString()); 
sw.Close(); 

Проблема выходной файл печати только 7/8 линии ALIST, в то время как AList фактически получил все 10 элементов. Интересно, относится ли это к потокобезопасности StringBuilder. Может кто-нибудь объяснить, почему не все строки выводятся?

+2

Это не Stringbuilder, это проблема здесь, это 'List ', который управляется параллельно. –

+0

@IanMercer нет его нет, прочитайте его вопрос, особенно последний абзац. _while AList фактически получил все 10 элементов ._ – CSharpie

+1

@kchpchan 1,10 в Parallel.For создает 9 элементов, а не 10, либо делает 0,10, либо 1,11 – CSharpie

ответ

2

В коде выше экземпляра StringBuilder никогда не обращались/модифицирована ничем, кроме main нити (или любой другой поток создает sw), так что нить-безопасность StringBuilder не актуальна однако у вас есть гораздо больше ошибка, которую вы всегда должны помнить при работе с несколькими потоками.

Никогда не изменять общий ресурс нескольких потоков, если этот ресурс не является поточно-

Вы обновляете AList из различных потоков, так как использовать lock для синхронизации доступа или потокобезопасного сбор, например ConcurrentQueue (заказ гарантировано) или ConcurrentBag (порядок не гарантируется)

Вы также добавление записи в AList вместо .

Наконец, это ваш модифицированный код, который дает ожидаемый результат.

var sw = new StreamWriter(@"ABC.txt"); 
try 
{   
    var AList = new List<AStruct>(); 

    var locker = new object(); 
    Parallel.For(0, 10, i =>       // generate 10 AStruct(s) 
    { 
     lock (locker) { AList.Add(new AStruct()); } 
    }); 

    var sb = new StringBuilder(); 
    for (int i = 0; i < AList.Count; i++)    //put in a StringBuilder 
    { 
     sb.AppendLine(AList[i].ToString()); 
    } 
    sw.Write(sb.ToString()); 
} finally 
{ 
    sw.Close(); 
} 
+2

Здесь, используя 'lock', сделайте' Parallel.For' бессмысленным. Одновременные коллекции действительно работают для меня. Благодаря! – kchpchan