如何防止在多线程应用程序中由List引起的InvalidOperationException?

时间:2019-06-24 15:12:58

标签: c# multithreading

我有2个Threads。其中一个反复修改 List。其他尝试访问 List,但通常会抛出System.InvalidOperationException

我尝试lock对象List,但没有帮助。

public static void Main()
{
    List<int> list = new List<int>();

    // A thread that repeatedly modifies the list
    Thread listAddThread = new Thread(() =>
    {
        while(true)
        {
            list.Add(0);
            Thread.Sleep(1);
        }
    });

    listAddThread.Start();

    // Wait to fill up the list
    Thread.Sleep(50);

    // Lock the list from other threads till the operation completes
    lock(list)
    {
        foreach(var entry in list)
        {
            DoSomeStuffThatTakesALotOfTime(entry);
        }
    }
}

public static void DoSomeStuffThatTakesALotOfTime(int i)
{
    Thread.Sleep(10);
    Console.WriteLine(i);
}

我希望lock(list)将阻止其他线程访问list

1 个答案:

答案 0 :(得分:2)

如果两个不同的代码块使用lock(list),则每个代码块都必须获得锁。一个将不会获取锁并执行,直到另一个已完成并释放锁。 (当然,这就是我们使用它的原因-以便两个代码块不会同时执行。)

但是在这种情况下,您只需要在方法的第二部分中使用一次lock。由于没有其他试图获取该锁的“竞争”代码,因此它根本不执行任何操作。

也不能保证listAddThread将在方法的第二部分开始迭代列表之前完成。这意味着您可能会开始尝试迭代列表,而您启动的其他线程正在向列表中添加该列表。根据例外情况,这可能不是-这就是 发生的情况。

while(true)循环将永远不会停止执行(true始终为true),因此无论等待时间是50ms还是5000ms,您都不会停止添加到列表中。但是,即使该循环确实终止了,也无法保证50ms等待将是足够的时间或太多的时间。最好只编写我们的代码,以便需要按顺序执行的所有内容总是始终按顺序执行,而不是试图猜测需要多长时间。