我有一个线程列表,我正在尝试让我的主线程等待列表中的所有线程终止:
while (consumers.Count > 0) consumers[0].Join();
问题是,这不是原子的,我可以得到“索引超出范围”的例外。
是否有任何原子方法来检查消费者[0]的存在并调用消费者[0] .Join()?
注意:我做不到
lock (myLocker) { if (consumers.Count > 0) consumers[0].Join(); }
因为我不想阻止其他线程在加入()时访问消费者。
答案 0 :(得分:5)
如果您没有在处应用任何同步但是您的列表正在从多个线程进行修改,那么您已经遇到了麻烦。其他一切都使用myLocker
吗?假设它确实如此:
while(true)
{
List<Thread> copy;
lock (myLocker)
{
copy = new List<Thread>(consumers);
}
if (copy.Count == 0)
{
break;
}
foreach (Thread thread in copy)
{
thread.Join();
}
}
请注意,此仅在保持锁定时访问consumers
,这是您应该在任何地方执行以实现线程安全的操作。在获取副本后,它还会在所有线程上调用Join
,而不是仅为每次迭代执行一次。
如果您知道此时线程不会被添加到列表中(例如,它是一个正在耗尽的线程池),您可以删除循环和检查:
List<Thread> copy;
lock (myLocker)
{
copy = new List<Thread>(consumers);
}
foreach (Thread thread in copy)
{
thread.Join();
}
答案 1 :(得分:0)
假设consumer [0]仅为null或具有预期方法的类的实例,您可以这样做
while (consumers.Count > 0)
{
if (consumers[0] != null)
{
consumers[0].Join();
}
}
答案 2 :(得分:0)
在您的场景中,当您只想等待线程时,为什么假设这些线程本身应该从列表中删除?确保只有主线程可以从列表中删除一个线程,在此线程终止后,它不会改变你的设计,你可以确定你不会访问它不存在的元素。你的循环看起来像这样:
for (int i = 0; i < consumers.Count; ++i)
consumers[i].Join();
//Now that you have joined everyone, just remove reference to your list
consumers = null;