处置不必是线程安全的

时间:2014-11-12 13:48:38

标签: .net multithreading garbage-collection dispose

在Jeffrey Richter的CLR中通过C#讨论Dispose方法。作者说:

  

但是,设计指南指出Dispose不一定是这样   线程安全的。原因是代码应该只在代码知道时才调用Dispose   事实上没有其他线程正在使用该对象。

这听起来与我相反。当然,如果一个类包装了本机或托管资源,一旦调用Dispose,它应该确保在尝试释放资源的同时没有其他调用者正在使用该资源。在我看来,知道有多少呼叫者正在使用资源的包装器比同时可能彼此不知道的所有不同呼叫者同步Dispose更容易。问题herehere也有类似问题,但他们确实没有明确答案。

这个设计指南背后的理由是什么?

1 个答案:

答案 0 :(得分:0)

Dispose经常忽略的一个关键点是它的目的不是对被处理的对象做任何事情,而是允许被处置的对象通知外部实体他们的服务不再需要。在许多情况下,外部实体可能被不同线程使用的许多对象共享。因此,在许多情况下,外部实体能够同时具有来自不同线程的多个通知或请求是很重要的。如果外部实体使用池来管理资源,则可能不需要担心对特定池项目执行的同时操作,但必须准备好它可能会收到多个同时请求以从/分配或释放项目。到同一个游泳池。

第二点是某些类型的通信库没有任何非阻塞方法,并且只支持一个多线程场景:阻塞的动作可能被任何线程异步中止。以这种方式中止动作将使通道处于不确定状态;在关闭并重新打开之前,该频道将无法再次使用。因为这样的中止会使信道处于无用状态,所以没有理由在发出中止后继续保持与之相关的任何资源。因此,一种常见且有用的模式是使用Dispose本身来执行中止。这样的中止必须从与对象的主线程分开的线程运行[如果对象的主线程被阻止,它就不能运行任何用户代码来触发中止!]它必须是线程安全的。请注意,实际的清理行为可能不一定在调用Dispose的线程上运行。如果在对象是"运行"时调用Dispose在其主线程上的代码(或者这样的代码在一个对象的方法中被阻塞)它可以设置一个标志来强制其主线程进行清理;如果在对象自己的线程未执行其代码时调用它,则该对象可以让正在调用Dispose的线程成为其主线程#34;然后清理它;如果它以前的"主线程"在清理期间尝试做某事,这样的行动会立即失败。

虽然在大多数情况下,Dispose在对象仍然在使用时不应被调用,但在某些情况下,如上所述,这将代表必要的使用场景。从消费者手中榨取资源可能是迫使消费者关闭的一种相当粗暴的方式,但在许多情况下,它可能比任何可用的替代方案更安全。此外,即使在物体不应处理但无论如何处理的情况下,Dispose方法应努力限制此类处置可能造成的伤害。如果在对象上仍然在使用它时调用Dispose会导致对象上的操作以不可预测的方式失败,那就没问题了。如果在仍在使用的一个对象上调用Dispose导致创建的下一个对象被赋予第一个对象仍然使用的资源,那就不太好了。无论Dispose是否以真正的线程安全方式运行,它应该确保不当使用造成的伤害将仅限于所处理的对象。