Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# NET中的线程没有在您希望清理的时候被清理_C#_.net - Fatal编程技术网

C# NET中的线程没有在您希望清理的时候被清理

C# NET中的线程没有在您希望清理的时候被清理,c#,.net,C#,.net,编辑 好消息是下面解释的奇怪行为与ConcurrentBag无关,也就是说:与ConcurrentBag相关的线程最终被释放。然而,由于某种或其他原因,线程本身仍然是活着的。在给出的示例代码中,我清楚地创建了一个线程并销毁了所有引用。然而,垃圾收集并不能将其收集起来。事实上,到目前为止,我所发现的线程被完全破坏的唯一时刻是当并发包本身被收集时(如果我不收集并发包,线程将保持活动状态),或者当我们创建许多其他线程时 原创(原创问题和一些动机。本部分下面的源代码解释了重要方面) 这是我几个月前就Co

编辑

好消息是下面解释的奇怪行为与ConcurrentBag无关,也就是说:与ConcurrentBag相关的线程最终被释放。然而,由于某种或其他原因,线程本身仍然是活着的。在给出的示例代码中,我清楚地创建了一个线程并销毁了所有引用。然而,垃圾收集并不能将其收集起来。事实上,到目前为止,我所发现的线程被完全破坏的唯一时刻是当并发包本身被收集时(如果我不收集并发包,线程将保持活动状态),或者当我们创建许多其他线程时

原创(原创问题和一些动机。本部分下面的源代码解释了重要方面)

这是我几个月前就ConcurrentBag()提出的一个问题的翻版。很明显,ConcurrentBag的行为不符合其应有的状态,现在我担心一些正在运行的遗留代码的稳定性。这个问题是为了回应我在回答以下问题时的发现:

情况一点也没有改变。我有一个处理消息的Web服务。客户端可以使用一些公共API插入消息。这些请求将由.NET线程池中的一个线程处理,该线程又将消息添加到ConcurrentBag中。接下来,有一些并发任务使用来自ConcurrentBag的消息并对其进行处理。在高峰时段,有许多消息被添加,许多消息被消耗,也有没有人做任何事情的时候。因此,线程池本身在运行期间会大量更改其活动线程的数量(所需的运行时间为“永远”)

现在发现,只要线程调用ConcurrentBag.Add(或ConcurrentBag上的任何方法)。线程通过ConcurrentBag中内部保存的引用保持活动状态,并且只有当ConcurrentBag本身被GC实际清理时才被释放。在我的场景中,由于ConcurrentBag在应用程序的整个生命周期中都是活动的,因此这将导致无限多的“浪费”线程没有被清理

之前给出的简单清空袋子的解决方案也没有帮助,因为没有问题。问题是(假定ConcurrentBag不调用它为当前线程保留的ThreadLocal上的Dispose,因为ConcurrentBag无法知道线程何时结束)。(不过,当你再次接触到袋子时,它应该进行清理)

也就是说,我们应该在大多数情况下停止使用ConcurrentBag,还是有解决方案可以添加到解决此问题中

我的测试代码:

        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字段。在我看来,它是假设线程存在于包实例中编写的。