class MultithreadOperation : IDisposable
{
private IList<Thread> operationThreads;
public void StartOperation()
{
// Initialize and start threads and put them to operationThreads
}
public void StopOperation()
{
// Aborts each thread.
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
disposed = true;
if (disposing)
{
// Release managed resources.
#1:
StopOperation();
}
// Release unmanaged resources.
#2:
StopOperation();
}
}
~MultithreadOperation()
{
Dispose(false);
}
}
实际上,如果放置实例,我需要停止所有线程。此外,如果实例被垃圾收集,我需要停止所有线程(否则,线程将仍然存活,这对我不利)。 当然,在位置#1中调用StopOperation()方法是完全合法的。
我想知道如果我们在第2位调用StopOperation()会有任何陷阱吗? 据我所知,当~MultithreadOperation()执行时,线程列表可能已被垃圾收集。另外,我已经看到很多建议,以避免任何代码引用Finalize实现中的托管资源,尤其是实例字段。
此外,听到有关此问题的不同方法会很有趣。 谢谢!
答案 0 :(得分:5)
这完全不合适。你的类的用户不熟悉细节会假设调用Dispose()会做一些无辜的事情。有点清理,没什么特别的。她将不期望程序处于完全不可预测的状态,线程会在随机位置中断该状态而无法恢复状态。
在终结器线程上也是完整的redrum,如果线程不处于可警告状态,则中止线程可能需要很多秒。 CLR将在2秒后中止终结器线程并终止程序,根本不提供有关程序崩溃的真正原因的诊断。
答案 1 :(得分:2)
在位置#2拨打StopOperation
是不安全的,因为:
List
个帖子或Thread
个实例本身。StopOperation
是否阻塞,直到所有线程都确认了停止信号,但如果确实存在,那么它可能会挂断终结器线程。另一点是,在这种情况下,您不应该中止线程(通过Thread.Abort
)。原因是中止在非确定性点向目标线程中注入带外(异步)异常。因为这些注入点是随机的(并且通常是非直观的),所以它可以在应用程序域甚至整个过程中破坏状态(通过在写入或其他更复杂操作的中间早期挽救)。
处理此问题的最佳方法是执行以下操作:
StopOperation
表示您选择的停止机制。通常,您希望等到所有线程都收到信号并自行关闭。您可以致电Thread.Join
。StopOperation
方法中调用Dispose
。现在我们如何处理那些不好玩的调用者并避免调用Dispose
?这有点棘手。我看到了处理这个问题的两种一般模式。
Thread.Interrupt
来戳戳线程,因为这需要引用Thread
实例。