我需要处理 SemaphoreSlim 吗
Do I need to Dispose a SemaphoreSlim
根据文档:
"a SemaphoreSlim
doesn't use a Windows kernel semaphore".
SemaphoreSlim
是否使用了任何特殊资源,这使得在 SemaphoreSlim
不再使用时调用 Dispose
变得很重要?
是的。
它可能使用一个 ManualResetEvent
,它使用一个 SafeWaitHandle
,这是一个 SafeHandle
,并且它有一个非托管句柄。
您可以在 reference source here.
中看到它
SafeHandle
是可终结的,因此如果您不处理它(通过处理 SemaphoreSlim
),它将进入需要为您执行此操作的终结器。由于终结器是单个线程,因此在某些情况下它可能会过度工作,因此始终建议处理可终结对象。
您应该始终在任何 class 实现 IDisposable
时调用 Dispose()
(或将其放在 using
语句中),而不是根据其内部实现做出决定。 class 作者已经通过实施 IDisposable
接口为您做出了这个决定。
如果您访问 AvailableWaitHandle
属性,则可以,您必须调用 Dispose()
来清理非托管资源。
如果您不访问 AvailableWaitHandle
,则否,调用 Dispose()
不会做任何重要的事情。
如果您访问 AvailableWaitHandle
,SemaphoreSlim
将根据需要创建一个 ManualResetEvent
。这可能很有用,例如,如果您需要等待多个句柄。如果您确实访问了 AvailableWaitHandle
属性,然后调用 Dispose()
失败,您将有一个泄漏的 ManualResetEvent
,它可能包装了一个非托管 CreateEvent
的句柄需要相应调用 CloseHandle
进行清理的资源。
正如其他张贴者所指出的,当您完成任何实现 IDisposable
的对象时,您 应该 调用 Dispose()
。在这种情况下,尽管从技术上讲这样做可能是安全的,但忽略这种做法会带来一些风险:
- 我的陈述基于对 .NET 4.6.1 的参考源代码。框架的某些未来版本将
SemaphoreSlim
更改为需要 Dispose()
的地方总是存在微小的(双关语意)可能性。
- 如果您的
SemaphoreSlim
暴露在您的 class 之外,调用代码可能会引用 AvailableWaitHandle
属性 而没有意识到您的 class 不是处置 SemaphoreSlim
并造成非托管资源泄漏。
对于许多其他 classes,我会同意 i3arnon,但对于 SemaphoreSlim,我会同意 Tim 的评论。如果您在低级别 class 中使用 SemaphoreSlim 并且必须处置它,那么实际上您程序中的所有内容都将变为 IDisposable,而实际上并没有必要。鉴于 AvailableWaitHandle 非常专业且通常不被使用,这更是如此。
为了防止其他编码人员访问 AvailableWaitHandle,您可以将其包装在非一次性 class 中。例如,您在 Cleary 和 Hanselman 的包装器中看到了这一点,它们都基于 Stephen Toub 的 post(顺便说一句,它没有 Dispose)。
P.S。至于 IDisposable 契约,只要在文档中说明只有在访问 AvailableWaitHandle 时才需要 Dispose。
根据文档:
"a
SemaphoreSlim
doesn't use a Windows kernel semaphore".
SemaphoreSlim
是否使用了任何特殊资源,这使得在 SemaphoreSlim
不再使用时调用 Dispose
变得很重要?
是的。
它可能使用一个 ManualResetEvent
,它使用一个 SafeWaitHandle
,这是一个 SafeHandle
,并且它有一个非托管句柄。
您可以在 reference source here.
中看到它SafeHandle
是可终结的,因此如果您不处理它(通过处理 SemaphoreSlim
),它将进入需要为您执行此操作的终结器。由于终结器是单个线程,因此在某些情况下它可能会过度工作,因此始终建议处理可终结对象。
您应该始终在任何 class 实现 IDisposable
时调用 Dispose()
(或将其放在 using
语句中),而不是根据其内部实现做出决定。 class 作者已经通过实施 IDisposable
接口为您做出了这个决定。
如果您访问 AvailableWaitHandle
属性,则可以,您必须调用 Dispose()
来清理非托管资源。
如果您不访问 AvailableWaitHandle
,则否,调用 Dispose()
不会做任何重要的事情。
AvailableWaitHandle
,SemaphoreSlim
将根据需要创建一个 ManualResetEvent
。这可能很有用,例如,如果您需要等待多个句柄。如果您确实访问了 AvailableWaitHandle
属性,然后调用 Dispose()
失败,您将有一个泄漏的 ManualResetEvent
,它可能包装了一个非托管 CreateEvent
的句柄需要相应调用 CloseHandle
进行清理的资源。
正如其他张贴者所指出的,当您完成任何实现 IDisposable
的对象时,您 应该 调用 Dispose()
。在这种情况下,尽管从技术上讲这样做可能是安全的,但忽略这种做法会带来一些风险:
- 我的陈述基于对 .NET 4.6.1 的参考源代码。框架的某些未来版本将
SemaphoreSlim
更改为需要Dispose()
的地方总是存在微小的(双关语意)可能性。 - 如果您的
SemaphoreSlim
暴露在您的 class 之外,调用代码可能会引用AvailableWaitHandle
属性 而没有意识到您的 class 不是处置SemaphoreSlim
并造成非托管资源泄漏。
对于许多其他 classes,我会同意 i3arnon,但对于 SemaphoreSlim,我会同意 Tim 的评论。如果您在低级别 class 中使用 SemaphoreSlim 并且必须处置它,那么实际上您程序中的所有内容都将变为 IDisposable,而实际上并没有必要。鉴于 AvailableWaitHandle 非常专业且通常不被使用,这更是如此。
为了防止其他编码人员访问 AvailableWaitHandle,您可以将其包装在非一次性 class 中。例如,您在 Cleary 和 Hanselman 的包装器中看到了这一点,它们都基于 Stephen Toub 的 post(顺便说一句,它没有 Dispose)。
P.S。至于 IDisposable 契约,只要在文档中说明只有在访问 AvailableWaitHandle 时才需要 Dispose。