假设我有这个类Logger
,它在一个低优先级工作线程中记录字符串,不是后台线程。字符串在Logger.WriteLine
中排队,并在Logger.Worker
中打磨。不允许丢失排队的字符串。粗略地这样(为了清楚起见,省略了实现,锁定,同步等):
public class Logger
{
private Thread workerThread;
private Queue<String> logTexts;
private AutoResetEvent logEvent;
private AutoResetEvent stopEvent;
// Locks the queue, adds the text to it and sets the log event.
public void WriteLine(String text);
// Sets the stop event without waiting for the thread to stop.
public void AsyncStop();
// Waits for any of the log event or stop event to be signalled.
// If log event is set, it locks the queue, grabs the texts and logs them.
// If stop event is set, it exits the function and the thread.
private void Worker();
}
由于工作线程是前台线程,因此如果进程应该能够完成,我必须能够确定地停止它。
问题:此方案中的一般建议是让Logger
实施IDisposable
并停止Dispose()
中的工作线程?像这样:
public class Logger : IDisposable
{
...
public void Dispose()
{
AsyncStop();
this.workerThread.Join();
}
}
还是有更好的处理方法吗?
答案 0 :(得分:3)
这肯定有用 - Thread
有资格作为资源等。IDisposable
的主要好处来自using
语句,所以它实际上取决于对象的所有者在单个方法中使用该对象持续一段时间 - 即
void Foo() {
...
using(var obj = YourObject()) {
... some loop?
}
...
}
如果这有意义(也许是工作泵),那么很好;对于抛出异常的情况,IDisposable
会有所帮助。如果不是典型用途,那么除了突出显示需要进行某种清理时,它就没那么有用了。< / p>
答案 1 :(得分:1)
这通常是最好的,只要你有一个确定的方法来处理记录器(在app的主要部分使用块,try / finally,shutdown handler等)。
答案 2 :(得分:1)
让线程将WeakReference保存到管理对象可能是个好主意,并定期检查以确保它仍然存在。从理论上讲,你可以使用终结器来轻推你的线程(请注意,终结器与Dispose不同,不应该执行Thread.Join),但是允许终结器失败的可能性是个好主意。
答案 3 :(得分:1)
您应该知道,如果用户没有手动调用Dispose(通过使用或其他方式),应用程序将永远不会退出,因为Thread对象将保留对Logger的强引用。 supercat提供的答案可以更好地解决这个问题。