C# NET中的线程没有在您希望清理的时候被清理
编辑 好消息是下面解释的奇怪行为与ConcurrentBag无关,也就是说:与ConcurrentBag相关的线程最终被释放。然而,由于某种或其他原因,线程本身仍然是活着的。在给出的示例代码中,我清楚地创建了一个线程并销毁了所有引用。然而,垃圾收集并不能将其收集起来。事实上,到目前为止,我所发现的线程被完全破坏的唯一时刻是当并发包本身被收集时(如果我不收集并发包,线程将保持活动状态),或者当我们创建许多其他线程时 原创(原创问题和一些动机。本部分下面的源代码解释了重要方面) 这是我几个月前就ConcurrentBag()提出的一个问题的翻版。很明显,ConcurrentBag的行为不符合其应有的状态,现在我担心一些正在运行的遗留代码的稳定性。这个问题是为了回应我在回答以下问题时的发现: 情况一点也没有改变。我有一个处理消息的Web服务。客户端可以使用一些公共API插入消息。这些请求将由.NET线程池中的一个线程处理,该线程又将消息添加到ConcurrentBag中。接下来,有一些并发任务使用来自ConcurrentBag的消息并对其进行处理。在高峰时段,有许多消息被添加,许多消息被消耗,也有没有人做任何事情的时候。因此,线程池本身在运行期间会大量更改其活动线程的数量(所需的运行时间为“永远”) 现在发现,只要线程调用ConcurrentBag.Add(或ConcurrentBag上的任何方法)。线程通过ConcurrentBag中内部保存的引用保持活动状态,并且只有当ConcurrentBag本身被GC实际清理时才被释放。在我的场景中,由于ConcurrentBag在应用程序的整个生命周期中都是活动的,因此这将导致无限多的“浪费”线程没有被清理 之前给出的简单清空袋子的解决方案也没有帮助,因为没有问题。问题是(假定ConcurrentBag不调用它为当前线程保留的ThreadLocal上的Dispose,因为ConcurrentBag无法知道线程何时结束)。(不过,当你再次接触到袋子时,它应该进行清理) 也就是说,我们应该在大多数情况下停止使用ConcurrentBag,还是有解决方案可以添加到解决此问题中 我的测试代码:C# NET中的线程没有在您希望清理的时候被清理,c#,.net,C#,.net,编辑 好消息是下面解释的奇怪行为与ConcurrentBag无关,也就是说:与ConcurrentBag相关的线程最终被释放。然而,由于某种或其他原因,线程本身仍然是活着的。在给出的示例代码中,我清楚地创建了一个线程并销毁了所有引用。然而,垃圾收集并不能将其收集起来。事实上,到目前为止,我所发现的线程被完全破坏的唯一时刻是当并发包本身被收集时(如果我不收集并发包,线程将保持活动状态),或者当我们创建许多其他线程时 原创(原创问题和一些动机。本部分下面的源代码解释了重要方面) 这是我几个月前就Co
Action collectAll = () =>
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
};
ConcurrentBag<object> bag = new ConcurrentBag<object>();
Thread producerThread = new Thread(new ThreadStart(delegate
{
// produce 1 item
bag.Add(new object());
}));
// create a weakreference to the newly created thread so we can track its status
WeakReference trackingReference = new WeakReference(producerThread);
// start the thread and let it complete
producerThread.Start();
producerThread.Join();
// thread can now be set to null, after a full GC collect, we assume that the thread is gone
producerThread = null;
collectAll();
Console.WriteLine("Thread is still alive: " + trackingReference.IsAlive); // returns true
// consume all items from the bag and collect again, the thread should surely be disposed by now
object output;
bag.TryTake(out output);
collectAll();
Console.WriteLine("Thread is still alive: " + trackingReference.IsAlive); // returns true
// ok, finally remove all references to the Bag
bag = null;
collectAll();
Console.WriteLine("Thread is still alive: " + trackingReference.IsAlive); // returns false
Action collectAll=()=>
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
};
ConcurrentBag=新ConcurrentBag();
Thread producerThread=新线程(新线程开始(委托
{
//制作一件物品
添加(新对象());
}));
//创建新创建线程的weakreference,以便跟踪其状态
WeakReference trackingReference=新的WeakReference(producerThread);
//启动线程并让它完成
producerThread.Start();
producerThread.Join();
//线程现在可以设置为null,在完成GC收集之后,我们假设线程已经消失
producerThread=null;
collectAll();
Console.WriteLine(“线程仍处于活动状态:“+trackingReference.IsAlive”);//返回true
//把袋子里所有的东西都吃光,然后再收集起来,现在一定要把线处理掉
对象输出;
袋子。TryTake(输出);
collectAll();
Console.WriteLine(“线程仍处于活动状态:“+trackingReference.IsAlive”);//返回true
//好的,最后删除对包的所有引用
bag=null;
collectAll();
Console.WriteLine(“线程仍处于活动状态:“+trackingReference.IsAlive”);//返回false
这么多单词,也许您可以将所有单词重新表述为只包含问题本身和问题描述?试着在里面做5-10行text@sll-也许,我在发布后发现了一些相互询问的结果。我更新了问题以帮助读者理解故事:)是的,是设计的。使用线程池线程或放弃集合类型。@HansPassant-我的最新发现表明,这与ConcurrentBag类没有什么关系。这些线程有自己的生命周期,与GC无关。查看我的编辑。你是那个意思吗?如果是这样,您能解释一下发生了什么吗?ConcurrentBag存储对Thread对象的引用。ConcurrentBag+ThreadLocalList.m_ownerThread字段。在我看来,它是假设线程存在于包实例中编写的。