C# 释放使用BlockingCollection的线程的最佳方法是什么?
我有一个类使用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()
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时是否真的会发生。。。你应该试试看。