Cui*_*崔鹏飞 12 c# parallel-processing concurrency multithreading task-parallel-library
以下代码解释了我的问题.我知道列表不是线程安全的.但是这个潜在的"真正"原因是什么?
class Program
{
static void Main(string[] args)
{
List<string> strCol = new List<string>();
for (int i = 0; i < 10; i++)
{
int id = i;
Task.Factory.StartNew(() =>
{
AddElements(strCol);
}).ContinueWith((t) => { WriteCount(strCol, id.ToString()); });
}
Console.ReadLine();
}
private static void WriteCount(List<string> strCol, string id)
{
Console.WriteLine(string.Format("Task {0} is done. Count: {1}. Thread ID: {2}", id, strCol.Count, Thread.CurrentThread.ManagedThreadId));
}
private static void AddElements(List<string> strCol)
{
for (int i = 0; i < 20000; i++)
{
strCol.Add(i.ToString());
}
}
}
Run Code Online (Sandbox Code Playgroud)
Mac*_*iej 21
我将跳过明显的答案"列表不是线程安全的" - 你已经知道了.
列表项保存在内部数组中.将项目添加到List时,至少有两个阶段(从逻辑的角度来看).首先,List获取一个索引,指示新项目的放置位置.它使用此索引将新项目放入数组中.然后它递增索引,这是第二阶段.如果第二个(或第三个,第四个......)线程同时添加新项目,则可能会有两个(3,4,...)新项目放入索引之前的同一个数组位置由第一个线程递增.项目被覆盖并丢失.
添加新项目和递增索引的内部操作必须始终一次完成,以使列表成为线程安全的.那就是所谓的关键部分.这可以通过锁来实现.
希望这能解释一下.
Ree*_*sey 13
这是因为List<T>不是线程安全的.
您应该为此使用线程安全集合,例如System.Collections.Concurrent中的一个集合.否则,你将需要同步所有访问权限List<T>(即:将每个Add调用放在一个锁中),这将完全打不过使用多个线程调用它的目的,因为在这种情况下你没有做任何其他工作.