StringBuilder并行线程安全

时间:2016-01-24 16:51:17

标签: c# parallel-for

我创建了一个结构,比如AStruct,并覆盖其ToString()方法。然后我写了一个并行for来返回一些AStruct并将它们放在一个列表中,这样我就可以使用StreamWriter来输出它们,比如

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的线程安全性有关。有人可以解释为什么不输出所有行?

1 个答案:

答案 0 :(得分:2)

在上面的代码中,StringBuilder的实例永远不会被main线程(或任何创建sw的线程)以外的任何东西访问/修改,所以StringBuilder的线程安全性{ {1}}不相关然而你有一个更大的错误,在处理多个帖子时你应该永远记住它。

  

除非这样,否则永远不要修改多个线程的共享资源   资源是线程安全的

您正在更新来自不同线程的AList,因此要么使用lock来同步访问权限,要么使用线程安全的集合,例如ConcurrentQueue(保证订单)或ConcurrentBag(订单无保证)

您还要将 9 条目添加到AList而不是 10

最后,这是您修改后的代码,它会产生预期的结果。

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