线程也在异常之后执行(调试期间)

时间:2011-05-04 09:20:38

标签: c# multithreading thread-safety

我正在尝试在一个线程中向ArrayList添加一些值,并在不使用任何锁或互斥锁的情况下从另一个线程中删除。虽然抛出了IndexOutOfRangeException但是removeThread应该只停在那里,但它确实没有!为什么呢?`

请查看以下代码:

class Program
{
    static ArrayList alist = new ArrayList();

    static void Main(string[] args)
    {
        Program p = new Program();
        Thread removeThread = new Thread(p.StartRemoval);
        Thread addThread = new Thread(p.StartAddition);
        addThread.Start();
        removeThread.Start();

        addThread .Join();
        removeThread.Join();

        //Console.ReadKey();
    }

    void StartRemoval()
    {
        for (int i = 0; i < 100000; i++)
            alist.Remove(i); // Exception
    }

    void StartAddition()
    {
        for (int i = 0; i < 100000; i++)
            alist.Add(i); 
    }
}

即使在removeThread中出现异常,它也会执行剩余的迭代。你能解释一下原因吗?

堆栈追踪:

at System.Collections.ArrayList.RemoveAt(Int32 index) at ConsoleApplication2.Program.StartRemoval() in Program.cs:line 34 at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart()

在下面的场景中,我已经超越了堆栈跟踪

  1. 将断点放在所有方法的最后一个大括号中。 (main,StartAddition,StartRemoval)

  2. 开始调试。

  3. 即使在异常之后,StartRemoval也会执行最后一行。

  4. 如果你在没有调试的情况下运行它,它可以正常工作。但堆栈跟踪是一样的。在代码中调用Remove,但在跟踪报告中跟踪RemoveAt

    感谢。

3 个答案:

答案 0 :(得分:2)

它不会抛出异常ArrayList.Remove只会抛出NotSupportedException而只是抛出

The ArrayList is read-only.

-or-

The ArrayList has a fixed size. 

有关详细信息,请参阅MSDN链接,您当前的代码不会执行任何操作以引发异常。

答案 1 :(得分:1)

在调试期间遇到异常的问题可能是代码与二进制文件不同步的结果。我不时看到这个。它并不经常发生,但我怀疑我们中的许多人多年来至少看过一次或两次。通常适用的解决方案是从Build菜单项中选择Rebuild Solution。

另外,请注意,此代码的行为通常是不可预测的,因为当文档声明此类型的实例不是时,您正在从多个线程访问对象(即ArrayList的实例)线程安全的。

答案 2 :(得分:0)

这个问题似乎是因为线程t1依赖于线程t2但反之亦然。线程t2可以愉快地将元素添加到数组列表的末尾,而不必担心容器中的内容(只要像您已经完成的那样正确分配了ArrayList)。

然而,线程t1取决于线程t2的作用。比如说线程t1想要从alist中删除元素5,它的可能线程t2仍在添加'5'并且它在alist中不存在,这会导致异常。 t1然后抛出此异常并完成执行。因为t2独立于t1(如上所述),所以它继续执行直到所有元素都被添加为止。

我相信以下内容可以解决这个问题:

t2.Start();    // Start t2 thread
t2.Join();     // Wait for thread t2 to add all elements to alist

t1.Start();    // Start t1 thread knowing all elements in alist have been added
t1.Join();     // Wait for thread t1 to complete execution

如果你可以在StartT1中尝试捕获异常并向我们发送你得到的确切异常,这可能有助于缩小目前的情况,但我认为上述情况很可能。

希望这有帮助。