C# 释放使用BlockingCollection的线程的最佳方法是什么?

C# 释放使用BlockingCollection的线程的最佳方法是什么?,c#,.net,multithreading,C#,.net,Multithreading,我有一个类使用BlockingCollection,如下所示: public class Logger : IDisposable { private BlockingCollection<LogMessage> _messages = null; private Thread _worker = null; private bool _started = false; public void Start()

我有一个类使用BlockingCollection,如下所示:

public class Logger : IDisposable
    {
        private BlockingCollection<LogMessage> _messages = null;
        private Thread _worker = null;
        private bool _started = false;

        public void Start() 
        {
            if (_started) return;
            //Some logic to open log file
            OpenLogFile();      
            _messages = new BlockingCollection<LogMessage>();  //int.MaxValue is the default upper-bound
            _worker = new Thread(Work) { IsBackground = true };
            _worker.Start();
            _started = true;
        }

        public void Stop()
        {   
            if (!_started) return;

            // prohibit adding new messages to the queue, 
            // and cause TryTake to return false when the queue becomes empty.
            _messages.CompleteAdding();

            // Wait for the consumer's thread to finish.
            _worker.Join();  

            //Dispose managed resources
            _worker.Dispose();
            _messages.Dispose();

            //Some logic to close log file
            CloseLogFile(); 

            _started = false;
        }

        /// <summary>
        /// Implements IDiposable 
        /// In this case, it is simply an alias for Stop()
        /// </summary>
        void IDisposable.Dispose() 
        {
            Stop();
        }

        /// <summary>
        /// This is message consumer thread
        /// </summary>
        private void Work()
        {
            LogMessage message;
            //Try to get data from queue
            while(_messages.TryTake(out message, Timeout.Infinite))
                WriteLogMessage(message); //... some simple logic to write 'message'
        }
    }

我创建了Logger类的一个新实例,调用它的Start方法。然后,如果我忘记在实例不再被引用时调用Dispose方法,那么工作线程将永远不会结束。这是一种内存泄漏。我说得对吗?如何克服这个问题?

您可以尝试在工作线程中只保留对BlockingCollection的弱引用,而不引用引用BlockingCollection的对象。我制作了一个静态方法,以确保我们不会引用这个记录器实例

这样,当集合不再被引用时,可以最终确定/收集集合。我不确定它是否有效,你必须尝试,这取决于TryTake是否能让收藏保持活力。它可能无法在调试中工作,因为GC的行为不同,所以请在未连接调试程序的发行版中尝试它

public class Logger : IDisposable
{
    private BlockingCollection<LogMessage> _messages = null;
    private Thread _worker = null;
    private bool _started = false;

    public void Start() 
    {
        if (_started) return;
        //Some logic to open log file
        OpenLogFile();      
        _messages = new BlockingCollection<LogMessage>();  //int.MaxValue is the default upper-bound
        _worker = new Thread(Work) { IsBackground = true };
        _worker.Start(new WeakReference<BlockingCollection<LogMessage>>(_messages));
        _started = true;
    }

    public void Stop()
    {   
        if (!_started) return;

        // prohibit adding new messages to the queue, 
        // and cause TryTake to return false when the queue becomes empty.
        _messages.CompleteAdding();

        // Wait for the consumer's thread to finish.
        _worker.Join();  

        //Dispose managed resources
        _worker.Dispose();
        _messages.Dispose();

        //Some logic to close log file
        CloseLogFile(); 

        _started = false;
    }

    /// <summary>
    /// Implements IDiposable 
    /// In this case, it is simply an alias for Stop()
    /// </summary>
    void IDisposable.Dispose() 
    {
        Stop();
    }

    /// <summary>
    /// This is message consumer thread
    /// </summary>
    private static void Work(object state)
    {
        LogMessage message;
        //Try to get data from queue
        do
        {
            BlockingCollection<LogMessage> messages;
            if (((WeakReference<BlockingCollection<LogMessage>>)state).TryGetTarget(out messages)
                && messages.TryTake(out message, Timeout.Infinite))
            {
                WriteLogMessage(message); //... some simple logic to write 'message'
                continue;
            }
        } while (false);
    }
}

我认为它不起作用,因为如果不调用BlockingCollection的CompleteAdding方法,messages.TryTake将永远阻塞。我可以为TryTake使用一个特定的超时,但我会使循环反复旋转。我认为当BlockingCollection完成时,它会“解除阻止”TryTake,但我不知道在您调用TryTake时是否真的会发生。。。你应该试试看。