这是释放使用BlockingCollection的线程的最佳方式
本文关键字:线程 最佳 方式 BlockingCollection 释放 | 更新日期: 2023-09-27 18:19:28
我有一个使用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方法,那么Worker线程将永远不会结束。这是一种内存泄漏。我说得对吗?以及如何克服这一点?
您可以尝试在工作线程中只保留对BlockingCollection
的弱引用,而不引用引用BlockingCollection
的对象。我制作了一个静态方法来确保我们不引用Logger实例this
。
这样,当集合不再被引用时,就可以最终确定/收集该集合。我不确定它是否能起作用,你必须尝试,这取决于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);
}
}