这是实际问题的示例代码
//Dictionary to hold unique keys
static Dictionary<int, int> list = new Dictionary<int, int>();
//Worker
static void Do(int index)
{
list.Add(index, index);
}
static void Main(string[] args)
{
int counter = 1000;
for (int i = 0; i < counter; i++)
{
int index = i;
System.Threading.Thread t = new System.Threading.Thread(
() => Do(index));
t.Start();
}
}
问题: list
并不总是包含1000个元素,因为传递给index
的{{1}}正在重复,并且线程正在崩溃。
我认为由于以下情况而出现问题
Do(index)
将传递给第一个线程index
被调用,但线程实际上并不是
开始了Start()
变为1 index
为1 index
,线程接收Start()
为1 index
的计数是1 这是在这种情况下发生的事情吗?解决方案是什么?
答案 0 :(得分:2)
至于为什么会发生这种情况,我猜想Matthew Watsons关于不等待最后一个退出线程的建议可能是正确的。
但我想补充一点,你可能不希望通过开始所有自己的线程来做到这一点。 Parallel.For将更有效地为您处理此问题,并解决所有事情完成时的问题。例如用这个替换上面的循环。
Parallel.For(0, counter, Do)
答案 1 :(得分:1)
该代码不应导致index
重复的问题(因为您已经避免了关闭问题)。但是,Dictionary<>
不是线程安全的,因此list.Add(index, index)
不安全。
您可以在添加到列表之前通过锁定解决该问题,如下所示:
static void Do(int index)
{
lock (list)
list.Add(index, index);
}
你还提到list.Count
并不总是正确的。这可能是因为您在最后一个线程完成添加之前检查了计数。
您可以在检查计数之前暂停一会儿来测试这个想法。 (但是,睡眠通常是错误的线程同步方法 - 但是对于这样的快速测试来说没问题。只是不要在生产代码中执行!)