Alb*_*lby 3 c# multithreading mutex
我编写了一个示例控制台应用程序,该应用程序创建了一个互斥体,如下面的代码示例所示。我通过按Ctrl + F5(不使用调试器运行该应用程序)直接从Visual Studio(VS2013)启动此应用程序。对于控制台应用程序的第一个实例,我获取了互斥锁,控制台中显示以下行:
已建立新执行个体...
但是,当我Ctrl + F5再次使用创建控制台应用程序的第二个实例时,我在控制台中收到以下消息:
实例已获取...
即使我使用以下代码行在500ms后明确释放了互斥锁:
mut.ReleaseMutex();
Run Code Online (Sandbox Code Playgroud)
在获取互斥量的同一线程中,我仍然看到控制台应用程序的第二个实例等待互斥量被释放。
有人可以向我解释为什么会这样,如果我做错了什么,可以纠正我吗?据我了解,ReleaseMutex应该从通过mut.WaitOne(0)调用获取该互斥锁的同一个线程中释放该互斥锁,以便应为所有等待获取互斥锁的线程提供所有权。但是,在这种情况下,我看不到它起作用。
如果我关闭获取互斥量的第一个实例(仍然是我的第二个实例),并尝试使用启动第三个实例Ctrl+F5,我可以看到有一个AbandonedMutexException:
未处理的异常:System.Threading.AbandonedMutexException:由于放弃了互斥,等待已完成。
PS:有趣的是,我可以通过将false互斥量构造函数作为
static Mutex mut = new Mutex(false, "Global\\test");
Run Code Online (Sandbox Code Playgroud)
这有什么意义initiallyOwned参数的
public Mutex(bool initiallyOwned, string name);
Run Code Online (Sandbox Code Playgroud)
互斥体类的构造函数版本?
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
因此,要了解一个问题,您需要了解两件事:
initiallyOwned参数如何工作如果Mutex使用initiallyOwned= true 创建-仅在尚未创建此类互斥体的情况下,它将尝试立即获取所有权BUT。因此,应用程序的第一个实例立即获得了互斥锁的所有权。它与执行操作大致相同:
var mut = new Mutex(false, "Global\\test");
mut.WaitOne();
Run Code Online (Sandbox Code Playgroud)
如果此互斥锁已经存在,它将不会尝试获取所有权。要查看是否创建了互斥锁(因此,它已经拥有它了),可以使用以下重载:
bool createdNew;
mut = new Mutex(true, "Global\\test", out createdNew);
Run Code Online (Sandbox Code Playgroud)
现在,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;
}
}
Run Code Online (Sandbox Code Playgroud)