如果我在以下代码中重用现有的 Mutex,为什么会得到一个新创建的 Mutex?
Why am I getting a newly created Mutex if I am reusing an existing one in the following code?
或不同的标题:
为什么处置获得的 Mutex 会破坏它?
我有以下代码,真正的代码在几个方法之间产生,并在这个方法休眠的地方做事:
bool createdNew;
using (Mutex mutex = new Mutex(true, "Global\AAA", out createdNew))
{
if (!createdNew)
{
throw new InvalidOperationException();
}
}
Thread.Sleep(15000);
using (Mutex mutex = new Mutex(false, "Global\AAA", out createdNew))
{
if (!createdNew)
{
mutex.ReleaseMutex();
}
else
{
throw new InvalidOperationException();
}
}
我期待第一次得到 createdNew = true,第二次得到 false,但我两次都得到 true。
它与处置有关,如果我不处置 Mutex
,那么一切都会按预期进行,但正如我在 here 等几个地方发现的那样,处置 Mutex
不会释放它(所以我猜它不会破坏它以及 Mutex
被当前线程获取)。
所以再说一次,为什么处置是摧毁一个获得的Mutex
?
因为互斥锁在最后一个句柄关闭时被销毁 (reference):
Use the CloseHandle function to close the handle. The system closes
the handle automatically when the process terminates. The mutex object
is destroyed when its last handle has been closed.
这就是您的示例中发生的情况 - 您创建了互斥量,然后(使用 using
)关闭了它的唯一句柄,因此它被销毁了。
请注意,您不应该像这样创建互斥量并在不释放互斥量的情况下关闭它的句柄:
Mutex mutex = new Mutex(true, "Global\AAA", out createdNew)
这表示 - 如果互斥体不存在,创建它并赋予该线程所有权。因此,如果在此调用后 createdNew
为真 - 您拥有此互斥锁,因此应该释放它。通过关闭句柄,您要么只是销毁互斥量(但这是无用的场景),要么放弃互斥量,以便其他 threads\processes 等待该互斥量并抛出 AbandonedMutexException
。所以应该是:
using (Mutex mutex = new Mutex(true, "Global\AAA", out createdNew)) {
if (!createdNew) {
throw new InvalidOperationException();
}
// do something useful
mutex.ReleaseMutex();
}
二次使用也不正确:
Mutex mutex = new Mutex(false, "Global\AAA", out createdNew)
通过将 false
作为第一个参数传递,您说:此互斥量是否已存在 - 不要将其所有权授予此线程。然后你做:
if (!createdNew)
{
mutex.ReleaseMutex();
}
但是此时您无论如何都不能拥有互斥体,所以即使控制流进入这个 if
块 - 它也不会工作(在 ReleaseMutex
上抛出异常)。相反,您应该显式调用 WaitOne
并忽略 createdNew
的结果(在这种情况下不相关):
using (Mutex mutex = new Mutex(false, "Global\AAA")) {
if (mutex.WaitOne()) {
// do something useful
mutex.ReleaseMutex();
}
}
那是因为 Dispose 方法关闭了 Mutex 的 WaitHandle(正如您在链接的问题的答案中看到的那样)
你正在做这样的事情
bool createdNew;
Mutex mutex = new Mutex(true, "Global\AAA", out createdNew);
if (!createdNew)
{
throw new InvalidOperationException();
}
mutex.SafeWaitHandle.Close();
从而破坏该互斥体的唯一句柄。
从您的代码中删除 using 位并调用
mutex.ReleaseMutex();
应该允许您稍后获得该互斥体的另一个句柄。
编辑:正如@Evk 指出的那样,当您关闭互斥锁的最后一个句柄时,它会自动销毁。
或不同的标题:
为什么处置获得的 Mutex 会破坏它?
我有以下代码,真正的代码在几个方法之间产生,并在这个方法休眠的地方做事:
bool createdNew;
using (Mutex mutex = new Mutex(true, "Global\AAA", out createdNew))
{
if (!createdNew)
{
throw new InvalidOperationException();
}
}
Thread.Sleep(15000);
using (Mutex mutex = new Mutex(false, "Global\AAA", out createdNew))
{
if (!createdNew)
{
mutex.ReleaseMutex();
}
else
{
throw new InvalidOperationException();
}
}
我期待第一次得到 createdNew = true,第二次得到 false,但我两次都得到 true。
它与处置有关,如果我不处置 Mutex
,那么一切都会按预期进行,但正如我在 here 等几个地方发现的那样,处置 Mutex
不会释放它(所以我猜它不会破坏它以及 Mutex
被当前线程获取)。
所以再说一次,为什么处置是摧毁一个获得的Mutex
?
因为互斥锁在最后一个句柄关闭时被销毁 (reference):
Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The mutex object is destroyed when its last handle has been closed.
这就是您的示例中发生的情况 - 您创建了互斥量,然后(使用 using
)关闭了它的唯一句柄,因此它被销毁了。
请注意,您不应该像这样创建互斥量并在不释放互斥量的情况下关闭它的句柄:
Mutex mutex = new Mutex(true, "Global\AAA", out createdNew)
这表示 - 如果互斥体不存在,创建它并赋予该线程所有权。因此,如果在此调用后 createdNew
为真 - 您拥有此互斥锁,因此应该释放它。通过关闭句柄,您要么只是销毁互斥量(但这是无用的场景),要么放弃互斥量,以便其他 threads\processes 等待该互斥量并抛出 AbandonedMutexException
。所以应该是:
using (Mutex mutex = new Mutex(true, "Global\AAA", out createdNew)) {
if (!createdNew) {
throw new InvalidOperationException();
}
// do something useful
mutex.ReleaseMutex();
}
二次使用也不正确:
Mutex mutex = new Mutex(false, "Global\AAA", out createdNew)
通过将 false
作为第一个参数传递,您说:此互斥量是否已存在 - 不要将其所有权授予此线程。然后你做:
if (!createdNew)
{
mutex.ReleaseMutex();
}
但是此时您无论如何都不能拥有互斥体,所以即使控制流进入这个 if
块 - 它也不会工作(在 ReleaseMutex
上抛出异常)。相反,您应该显式调用 WaitOne
并忽略 createdNew
的结果(在这种情况下不相关):
using (Mutex mutex = new Mutex(false, "Global\AAA")) {
if (mutex.WaitOne()) {
// do something useful
mutex.ReleaseMutex();
}
}
那是因为 Dispose 方法关闭了 Mutex 的 WaitHandle(正如您在链接的问题的答案中看到的那样)
你正在做这样的事情
bool createdNew;
Mutex mutex = new Mutex(true, "Global\AAA", out createdNew);
if (!createdNew)
{
throw new InvalidOperationException();
}
mutex.SafeWaitHandle.Close();
从而破坏该互斥体的唯一句柄。
从您的代码中删除 using 位并调用
mutex.ReleaseMutex();
应该允许您稍后获得该互斥体的另一个句柄。
编辑:正如@Evk 指出的那样,当您关闭互斥锁的最后一个句柄时,它会自动销毁。