我正在尝试在一个线程中向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()
在下面的场景中,我已经超越了堆栈跟踪
将断点放在所有方法的最后一个大括号中。 (main,StartAddition,StartRemoval)
开始调试。
即使在异常之后,StartRemoval也会执行最后一行。
如果你在没有调试的情况下运行它,它可以正常工作。但堆栈跟踪是一样的。在代码中调用Remove
,但在跟踪报告中跟踪RemoveAt
。
感谢。
答案 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中尝试捕获异常并向我们发送你得到的确切异常,这可能有助于缩小目前的情况,但我认为上述情况很可能。
希望这有帮助。