从Visual Studio启动时,C#ReleaseMutex()未在控制台应用程序的多个实例中释放互斥体
我已经编写了一个示例控制台应用程序,它创建了一个互斥锁,如下面的示例代码所示。我直接从VisualStudio(VS2013)启动此应用程序,方法是按Ctrl+F5(在不使用调试器的情况下运行应用程序)。对于console应用程序的第一个实例,我获取互斥,console中显示以下行: 已创建新实例 但是,当我再次使用Ctrl+F5创建console应用程序的第二个实例时,控制台中会显示以下消息: 实例已获取 即使我使用这行代码在500毫秒后显式释放互斥:从Visual Studio启动时,C#ReleaseMutex()未在控制台应用程序的多个实例中释放互斥体,c#,multithreading,mutex,C#,Multithreading,Mutex,我已经编写了一个示例控制台应用程序,它创建了一个互斥锁,如下面的示例代码所示。我直接从VisualStudio(VS2013)启动此应用程序,方法是按Ctrl+F5(在不使用调试器的情况下运行应用程序)。对于console应用程序的第一个实例,我获取互斥,console中显示以下行: 已创建新实例 但是,当我再次使用Ctrl+F5创建console应用程序的第二个实例时,控制台中会显示以下消息: 实例已获取 即使我使用这行代码在500毫秒后显式释放互斥: mut.ReleaseMutex();
mut.ReleaseMutex();
在获取互斥体的同一线程中,我仍然看到我的第二个控制台应用程序实例等待释放互斥体
有人能给我解释一下为什么会这样,或者如果我做错了什么就纠正我吗?如果我理解,ReleaseMutex
应该从通过mut.WaitOne(0)
调用获取互斥体的同一线程中释放互斥体,以便向等待获取互斥体的任何其他线程提供所有权。然而,在这种情况下,我无法看到它的工作
如果我关闭获取互斥锁的第一个实例(我的第二个实例仍处于活动状态),并尝试使用Ctrl+F5启动第三个实例,我可以看到有一个放弃的mutexception
:
未处理的异常:System.Threading.ForwardedMutexException:由于放弃了互斥锁,等待已完成
PS:有趣的是,如果我将互斥构造函数中的false
作为
static Mutex mut = new Mutex(false, "Global\\test");
initiallyOwned
参数在
public Mutex(bool initiallyOwned, string name);
互斥类的构造函数版本
因此,要理解一个问题,你需要了解两件事:
initiallyOwned
参数的工作原理互斥体时初始拥有
=true,则它将尝试立即获取所有权,但前提是尚未创建此类互斥体。因此,应用程序的第一个实例立即获得互斥对象的所有权。这与执行以下操作大致相同:
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
参数(而且互斥体还不存在并且已经创建),第二次是显式调用它。但您只调用一次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;
}
}
如果将true
作为initiallyOwned
传递,当前线程将在创建互斥锁后立即尝试获取互斥锁。@Leandro Taset是的,我理解这一点,但为什么调用mut.ReleaseMutex()同一线程上的代码>未释放互斥锁??这就是我试图理解的。有趣的是,使用false
可以很好地工作,为什么不使用true
呢。如果打算这样做,在哪些情况下应该使用true
,在哪些情况下应该使用false
。正如@LeandroTaset所说,这种模式被打破,因为它会导致放弃互斥。请参阅答案。“它打算这样工作”-不,如果运行第一个副本,它将占用互斥锁(由于构造函数参数),但在WaitOne
check=no release=废弃互斥锁时将失败WaitOne
不是“检查此线程是否拥有所有权”,而是“尝试获取所有权”,因此它将返回false
(因为某些线程已经拥有互斥锁)。阅读更多关于@Evk的信息,谢谢你的解释。我现在已经澄清了我的疑问..谢谢@Evk。。您已经清楚地解释了我的问题的解决方案。我知道我调用mut.WaitOne()
的次数是我必须调用mut.ReleaseMutex
,但我从来都不知道var mut=new Mutex(true,“Global\\test”)
相当于var mut=new Mutex(false,“Global\\test”);mut.WaitOne()代码>。这个解释让我明白了为什么我不能在我的应用程序的第二个实例中获得互斥。
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;
}
}