从 Visual Studio 启动时,C# ReleaseMutex() 未在控制台应用程序的多个实例中释放互斥量
C# ReleaseMutex() is not releasing mutex in multiple instances of console application while launching from Visual Studio
我编写了一个示例控制台应用程序,它创建了一个互斥锁,如下面的代码示例所示。我通过按 Ctrl + F5 直接从 Visual Studio (VS2013) 启动此应用程序(运行 没有调试器的应用程序)。对于控制台应用程序的第一个实例,我获取了互斥锁,控制台中显示了以下行:
New Instance created...
但是,当我再次使用 Ctrl + F5 创建控制台应用程序的第二个实例时,我在控制台中收到以下消息:
Instance already acquired...
即使我使用这行代码在 500 毫秒后显式释放互斥量:
mut.ReleaseMutex();
在获取互斥锁的同一个线程中,我仍然看到我的第二个控制台应用程序实例正在等待释放互斥锁。
有人可以向我解释为什么会这样或者如果我做错了什么请纠正我吗?如果我理解,ReleaseMutex
应该从通过 mut.WaitOne(0)
调用获取互斥锁的同一个线程释放互斥锁,以便应为任何其他等待获取互斥锁的线程提供所有权。但是,在这种情况下,我无法看到它工作。
如果我关闭获得互斥量的第一个实例(我的第二个实例仍然存在)并尝试使用 Ctrl+F5 启动第三个实例,我可以看到有一个AbandonedMutexException
:
Unhandled Exception: System.Threading.AbandonedMutexException: The wait completed due to an abandoned mutex.
PS:有趣的是,如果我在互斥构造函数中将 false
作为
传递,我可以看到它工作正常
static Mutex mut = new Mutex(false, "Global\test");
中的initiallyOwned
参数有什么意义
public Mutex(bool initiallyOwned, string name);
互斥量的构造函数版本class?
Console output for 2 instances run from VS
class Program
{
static Mutex mut = new Mutex(true, "Global\test");
static void Main(string[] args)
{
if (IsInstance())
{
Console.WriteLine("New Instance created...");
}
else
{
Console.WriteLine("Instance already acquired...");
}
Console.ReadLine();
}
static bool IsInstance()
{
if (!mut.WaitOne(0))
{
Console.WriteLine("Thread id {0} Waiting at Mutex...",AppDomain.GetCurrentThreadId());
return false;
}
else
{
Console.WriteLine("Thread id {0} got Mutex...", AppDomain.GetCurrentThreadId());
Thread.Sleep(500);
mut.ReleaseMutex();
return true;
}
}
}
所以要理解一个问题,您需要了解两件事:
initiallyOwned
参数如何工作
- 互斥可重入(递归调用)。
如果您使用 initiallyOwned
= true 创建 Mutex
- 它会尝试立即获取所有权,但前提是尚未创建此类互斥体。因此,您的应用程序的第一个实例会立即获得互斥体的所有权。这与做的差不多:
var mut = new Mutex(false, "Global\test");
mut.WaitOne();
如果这个互斥量已经存在,它不会尝试获取所有权。要查看是否创建了互斥体(如果你已经拥有它),你可以使用这个重载:
bool createdNew;
mut = new Mutex(true, "Global\test", out createdNew);
现在,Mutex
允许从同一线程多次调用 WaitOne
和 ReleaseMutex
。如果您多次调用 WaitOne
- 您需要调用 ReleaseMutex
相同的次数才能释放它。但是,对于您的第一个实例,您调用了 WaitOne
两次:第一次是因为 initiallyOwned
参数(并且因为 mutex 尚不存在并且已创建),第二次您显式调用它。但是你只调用 ReleaseMutex
一次,因此你的互斥锁不会被释放并且由第一个实例拥有。当您关闭此实例时 - 互斥仍未释放,因此被放弃。
这是一个说明这些要点的代码示例:
static Mutex mut;
static void Main(string[] args)
{
bool createdNew;
mut = new Mutex(true, "Global\test", out createdNew);
if (createdNew) {
Console.WriteLine("New instance created with initially owned = true");
}
else if (IsInstance())
{
Console.WriteLine("New Instance created...");
}
else
{
Console.WriteLine("Instance already acquired...");
}
if (createdNew)
{
Thread.Sleep(500);
mut.ReleaseMutex();
}
Console.ReadLine();
}
static bool IsInstance()
{
if (!mut.WaitOne(0))
{
Console.WriteLine("Thread id {0} Waiting at Mutex...", AppDomain.GetCurrentThreadId());
return false;
}
else
{
Console.WriteLine("Thread id {0} got Mutex...", AppDomain.GetCurrentThreadId());
Thread.Sleep(500);
mut.ReleaseMutex();
return true;
}
}
我编写了一个示例控制台应用程序,它创建了一个互斥锁,如下面的代码示例所示。我通过按 Ctrl + F5 直接从 Visual Studio (VS2013) 启动此应用程序(运行 没有调试器的应用程序)。对于控制台应用程序的第一个实例,我获取了互斥锁,控制台中显示了以下行:
New Instance created...
但是,当我再次使用 Ctrl + F5 创建控制台应用程序的第二个实例时,我在控制台中收到以下消息:
Instance already acquired...
即使我使用这行代码在 500 毫秒后显式释放互斥量:
mut.ReleaseMutex();
在获取互斥锁的同一个线程中,我仍然看到我的第二个控制台应用程序实例正在等待释放互斥锁。
有人可以向我解释为什么会这样或者如果我做错了什么请纠正我吗?如果我理解,ReleaseMutex
应该从通过 mut.WaitOne(0)
调用获取互斥锁的同一个线程释放互斥锁,以便应为任何其他等待获取互斥锁的线程提供所有权。但是,在这种情况下,我无法看到它工作。
如果我关闭获得互斥量的第一个实例(我的第二个实例仍然存在)并尝试使用 Ctrl+F5 启动第三个实例,我可以看到有一个AbandonedMutexException
:
Unhandled Exception: System.Threading.AbandonedMutexException: The wait completed due to an abandoned mutex.
PS:有趣的是,如果我在互斥构造函数中将 false
作为
static Mutex mut = new Mutex(false, "Global\test");
中的initiallyOwned
参数有什么意义
public Mutex(bool initiallyOwned, string name);
互斥量的构造函数版本class?
Console output for 2 instances run from VS
class Program
{
static Mutex mut = new Mutex(true, "Global\test");
static void Main(string[] args)
{
if (IsInstance())
{
Console.WriteLine("New Instance created...");
}
else
{
Console.WriteLine("Instance already acquired...");
}
Console.ReadLine();
}
static bool IsInstance()
{
if (!mut.WaitOne(0))
{
Console.WriteLine("Thread id {0} Waiting at Mutex...",AppDomain.GetCurrentThreadId());
return false;
}
else
{
Console.WriteLine("Thread id {0} got Mutex...", AppDomain.GetCurrentThreadId());
Thread.Sleep(500);
mut.ReleaseMutex();
return true;
}
}
}
所以要理解一个问题,您需要了解两件事:
initiallyOwned
参数如何工作- 互斥可重入(递归调用)。
如果您使用 initiallyOwned
= true 创建 Mutex
- 它会尝试立即获取所有权,但前提是尚未创建此类互斥体。因此,您的应用程序的第一个实例会立即获得互斥体的所有权。这与做的差不多:
var mut = new Mutex(false, "Global\test");
mut.WaitOne();
如果这个互斥量已经存在,它不会尝试获取所有权。要查看是否创建了互斥体(如果你已经拥有它),你可以使用这个重载:
bool createdNew;
mut = new Mutex(true, "Global\test", out createdNew);
现在,Mutex
允许从同一线程多次调用 WaitOne
和 ReleaseMutex
。如果您多次调用 WaitOne
- 您需要调用 ReleaseMutex
相同的次数才能释放它。但是,对于您的第一个实例,您调用了 WaitOne
两次:第一次是因为 initiallyOwned
参数(并且因为 mutex 尚不存在并且已创建),第二次您显式调用它。但是你只调用 ReleaseMutex
一次,因此你的互斥锁不会被释放并且由第一个实例拥有。当您关闭此实例时 - 互斥仍未释放,因此被放弃。
这是一个说明这些要点的代码示例:
static Mutex mut;
static void Main(string[] args)
{
bool createdNew;
mut = new Mutex(true, "Global\test", out createdNew);
if (createdNew) {
Console.WriteLine("New instance created with initially owned = true");
}
else if (IsInstance())
{
Console.WriteLine("New Instance created...");
}
else
{
Console.WriteLine("Instance already acquired...");
}
if (createdNew)
{
Thread.Sleep(500);
mut.ReleaseMutex();
}
Console.ReadLine();
}
static bool IsInstance()
{
if (!mut.WaitOne(0))
{
Console.WriteLine("Thread id {0} Waiting at Mutex...", AppDomain.GetCurrentThreadId());
return false;
}
else
{
Console.WriteLine("Thread id {0} got Mutex...", AppDomain.GetCurrentThreadId());
Thread.Sleep(500);
mut.ReleaseMutex();
return true;
}
}