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

C# 线程在异常之后也执行(在调试期间),c#,multithreading,thread-safety,C#,Multithreading,Thread Safety,我试图在一个线程中向ArrayList添加一些值,并在不使用任何锁或互斥锁的情况下从另一个线程中删除这些值。当删除一个索引时,抛出一个异常,removeThread应该只在那里停止,但它不会!为什么?` 请看以下代码: class Program { static ArrayList alist = new ArrayList(); static void Main(string[] args) { Program p = new Program();

我试图在一个线程中向ArrayList添加一些值,并在不使用任何锁或互斥锁的情况下从另一个线程中删除这些值。当删除一个
索引时,抛出一个
异常,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); 
    }
}
类程序
{
静态ArrayList alist=新的ArrayList();
静态void Main(字符串[]参数)
{
程序p=新程序();
线程移除线程=新线程(p.startremova);
螺纹添加螺纹=新螺纹(p.startadition);
addThread.Start();
removeThread.Start();
addThread.Join();
removeThread.Join();
//Console.ReadKey();
}
void startremova()
{
对于(int i=0;i<100000;i++)
alist.Remove(i);//异常
}
无效起始条件()
{
对于(int i=0;i<100000;i++)
2.添加(i);
}
}
即使在
removeThread
中出现异常之后,它也会执行剩余的迭代。你能解释一下原因吗

堆栈跟踪:

位于System.Collections.ArrayList.RemoveAt(Int32索引)
在Program.cs中的ConsoleApplication2.Program.StartRecoval()处:第34行
在System.Threading.ExecutionContext.Run(ExecutionContext ExecutionContext,ContextCallback回调,对象状态)
位于System.Threading.ThreadHelper.ThreadStart()

在下面的场景中,我得到了堆栈跟踪

  • 将断点放在所有方法的最后一个大括号中。(主、STARTADition、StartRemoval)

  • 开始调试

  • startremova即使在异常之后也会执行最后一行

  • 如果您在未调试的情况下运行它,它将正常工作。但是堆栈跟踪是相同的<代码>删除
    在代码中被调用,但
    删除
    在跟踪报告中被跟踪


    谢谢。

    它不会抛出异常,只会在何时抛出

    The ArrayList is read-only.
    
    -or-
    
    The ArrayList has a fixed size. 
    

    有关详细信息,请参阅MSDN链接,您当前的代码不会引发异常。

    它不会引发异常,只是在发生异常时引发异常

    The ArrayList is read-only.
    
    -or-
    
    The ArrayList has a fixed size. 
    

    有关详细信息,请参阅MSDN链接,您当前的代码不会引发异常。

    问题似乎是由于线程t1依赖于线程t2,而不是线程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
    
    如果您可以在Start1中的异常周围放置一个try catch,并将您得到的确切异常发布给我们,这可能有助于准确地缩小发生的情况,但我认为上述情况最有可能发生


    希望这能有所帮助。

    这个问题似乎是因为线程t1依赖于线程t2,而不是线程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
    
    如果您可以在Start1中的异常周围放置一个try catch,并将您得到的确切异常发布给我们,这可能有助于准确地缩小发生的情况,但我认为上述情况最有可能发生


    希望这能有所帮助。

    调试过程中出现的异常问题可能是由于代码与二进制文件不同步造成的。我时常看到这一点。这种情况并不经常发生,但我怀疑我们中的许多人多年来至少见过一两次。通常适用于的解决方案是从“生成”菜单项中选择“重建解决方案”


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

    在调试期间,您看到的异常问题可能是代码与二进制文件不同步的结果。我时常看到这一点。这种情况并不经常发生,但我怀疑我们中的许多人多年来至少见过一两次。通常适用于的解决方案是从“生成”菜单项中选择“重建解决方案”


    另外,请注意,此代码的行为通常是不可预测的,因为当文档声明此类型的实例不是线程安全的时,您正在从多个线程访问对象(即
    ArrayList
    )。我怀疑你的诊断有误。你是说t2一直在运行吗?t1将在抛出未捕获的异常时结束。Thread1似乎在做的任何事情都是无关的。您正在以非线程安全的方式使用ArrayList。@Jon:我尝试过多次执行它,但都是相同的行为@Russell:即使在异常之后,也没有相同的线程继续运行@希恩德尔:没有@亨克:是的,但是线是错的