我是否需要处理SemaphoreSlim

Tom*_*eyn 20 .net c# dispose semaphore idisposable

根据文件:

"a SemaphoreSlim不使用Windows内核信号量".

是否有任何特殊资源SemaphoreSlim使得DisposeSemaphoreSlim不再使用遗嘱时呼叫很重要?

小智 18

如果您访问AvailableWaitHandle属性,然后是,则必须调用Dispose()来清理非托管资源.

如果您没有访问AvailableWaitHandle,那么调用Dispose()将不会执行任何重要操作.

如果您访问AvailableWaitHandle,SemaphoreSlim将根据需要创建ManualResetEvent.这可能很有用,例如,如果您需要等待多个句柄.如果您确实访问了AvailableWaitHandle属性,然后无法调用Dispose(),则会有一个泄漏的ManualResetEvent,它可能会包含一个非托管CreateEvent资源的句柄,该资源需要对CloseHandle进行相应的调用以进行清理.

正如其他海报所指出的,当你完成任何实现IDisposable的对象时,你应该调用Dispose().在这种情况下,忽略这种做法存在一些风险,即使在技术上可能是安全的:

  1. 我的陈述基于.NET 4.6.1的参考源代码.总是有一种纤细(双关语)的可能性,框架的某些未来版本会将SemaphoreSlim更改为需要Dispose()的地方.
  2. 如果您的SemaphoreSlim暴露在您的类之外,则调用代码可能会引用AvailableWaitHandle属性,而不会意识到您的类没有处置SemaphoreSlim并创建非托管资源泄漏.


i3a*_*non 11

是.

它可以使用a ManualResetEvent使用a SafeWaitHandle是a SafeHandle并且它具有非托管句柄.

您可以在参考源中看到它.

SafeHandle是最终的,所以如果你不处理它(通过处置SemaphoreSlim),它将转到需要为你做的终结器.由于终结器是单线程,因此在某些情况下可能会过度工作,因此始终建议配置可终结的对象.

  • 仅当调用AvailableWaitHandle 时才会创建SafeHandle。如果您仅在不调用AvailableWaitHandle的包装器中使用SemaphoreSlim(正如我下面建议的那样),则不会发生最终化/处置问题。 (3认同)

sjb*_*sjb 8

对于许多其他类,我会同意 i3arnon,但对于 SemaphoreSlim,我会同意 Tim 的评论。如果您在低级类中使用 SemaphoreSlim 并且必须处置它,那么实际上您程序中的所有内容都将变成 IDisposable,而实际上这是不必要的。鉴于AvailableWaitHandle 非常专业并且通常不被使用,这一点就更正确了。

为了防止其他编码人员访问AvailableWaitHandle,您可以将其包装在非一次性类中。例如,您可以在 Cleary 和 Hanselman 的包装器中看到这一点,这两个包装器都基于 Stephen Toub 的帖子(顺便说一下,该帖子不属于 Dispose)。

PS 对于 IDisposable 合约,只需在文档中指定只有在访问 AvailableWaitHandle 时才需要 Dispose 即可。


Dam*_*Arh 5

您应该始终调用Dispose()任何实现类IDisposable(或将其放在using语句中),而不是根据其内部实现做出决定。类作者已经通过实现IDisposable接口为您做出了决定。

  • 实现“IDisposable”的决定可能并不总是由类作者决定。有许多接口,例如`IEnumerator<T>`,它们继承了`IDisposable`,以允许*某些*实现在使用后需要清理的可能性。即使实现`IEnumerable<T>`的类的契约指定其特定的`GetEnumerator`实现将始终返回一个可以安全放弃的对象,任何由`IEnumerable<T>.GetEnumerator`返回的对象也必须无论是否需要清理,都实现`IDisposable`。 (5认同)
  • 这确实是一般规则。我的问题具体是关于 SemaphoreSlim 的。请注意,SemaphoreSlim 用例通常不适合使用“使用”。 (3认同)