我应该处置互斥锁吗?

Posted

技术标签:

【中文标题】我应该处置互斥锁吗?【英文标题】:Should I dispose a Mutex? 【发布时间】:2011-08-18 12:01:07 【问题描述】:

我正在开发 2 个 Windows 服务,它们有一个公共数据库,我想用系统互斥锁锁定(跨进程)。

现在我想知道在try-finally 块中调用WaitOne()ReleaseMutex() 是否可以,或者我是否也应该处理互斥锁(例如在using 块中)。如果是这样,我想我应该总是在 WaitOne() 方法上捕获 AbandonedMutexException 还是我错了?

【问题讨论】:

您需要 AbandonedMutexException 来告诉您拥有互斥锁的服务已意外终止。在这种情况下,您必须停止使用 dbase 并等待其他服务再次启动。使用第三个进程作为仲裁者是明智的。 【参考方案1】:

互斥锁是一个 Windows 内核对象(这里包装在一个 .NET 对象中)。

因此,它是一个应该被释放的非托管资源。

更准确地说,.NET 对象包含互斥体的句柄,必须以某种方式释放/处置。

我不相信没有释放互斥对象的code sample in the Mutex class docs。尽管 Henzi 有一个很好的评论点:Mutex 对象是静态的,并且会在进程退出时由终结器处置或由 Windows 内核销毁。

另外,请注意Close() 也会处理该对象。

当然,将现有的 Mutex 对象保留在您的应用程序中并没有错,即使您不使用它也是如此。它们是轻资源。

【讨论】:

没有留下代码示例,你必须链接它:msdn.microsoft.com/en-us/library/system.threading.mutex.aspx 但是由于我正在创建 Windows 服务,我认为我不应该在我的服务的“运行时”期间进行处理(总是如此)。每次创建一个具有相同名称的新 Mutex 实例只会包装相同的非托管实例,对吗?还是会一遍又一遍地创建新的非托管资源?当我的一项服务停止以真正清理它时,我可以关闭互斥锁吗? 在代码示例中,创建了一个互斥体,它存储在一个静态字段中,并在应用程序的整个持续时间内使用。当应用程序终止时,会自动调用终结器。那么,处置该互斥体有什么意义呢? (不过,我确实同意你的观点,一般所有 IDisposable 对象都应该被释放。我只是不同意代码示例中缺少某些东西的事实。) Serge,我认为问题在于这个互斥锁将由两个 Windows 服务共享。因此,必须停止两者才能运行终结器。如果某些东西实现了 IDisposable,请始终确保调用 Dispose。 否 - 每个进程都有自己的 HANDLE...所以终结器只会删除那个 HANDLE...当没有更多 HANDLE 时,内核对象本身最终会被 Windows 销毁(在此示例中= 没有更多的进程)到那个 Mutex...【参考方案2】:

根据this,当最后一个持有该互斥体的HANDLE 的进程结束时,名为Mutex 的名称会自动销毁。

在非托管术语中,MSDN 说

使用CloseHandle 函数关闭句柄。当进程终止时,系统会自动关闭句柄。互斥对象在其最后一个句柄关闭时被销毁。

在 .NET 中,您应该在 Mutex 上调用 .Close() - 这会释放 HANDLE... 因为每个进程在访问相同名称的 HANDLE 时都会获得自己的 HANDLE,这是一致的做法。 .. 不调用 Close() 不会留下任何问题,一旦进程不再(终结器和所有)......

【讨论】:

【参考方案3】:

您需要释放等待句柄使用的资源。

来自文档:

释放当前 WaitHandle 实例使用的所有资源 班级。 (继承自 WaitHandle。)

等待句柄使用非托管资源,应在使用结束时释放。

MSDN Documentation Mutex

【讨论】:

以上是关于我应该处置互斥锁吗?的主要内容,如果未能解决你的问题,请参考以下文章

使用互斥锁后程序仍然崩溃(我可以在同一个线程中使用互斥锁吗?)

我可以使用联锁操作来更新多个值以避免锁定关键部分/互斥锁吗?

你了解多线程自旋锁互斥锁递归锁等锁吗?

C#多线程 一个缓冲队列,一个生产者线程,一个消费者线程,这两个线程同时操作这个队列,必须加互斥锁吗

在我的情况下是不是需要互斥锁[关闭]

c++11 进程间原子和互斥锁