互斥对象会自己关闭吗?
本文关键字:自己 对象 | 更新日期: 2023-09-27 17:50:58
我想知道什么时候是使用ReleaseMutex
的合适时间,什么时候是使用Close
的合适时间
我们正在(有效地)用c#编写一个"自动更新"类型的应用程序。用户可以同时运行多个自动更新程序实例,但是每个实例都必须等待其他实例完成后才能继续运行。因此,应用程序流程如下:
- 启动更新程序,创建互斥锁(
new Mutex(false, "MyMutex", out isCreator)
) - 检查当前运行的实例(
Mutex.WaitOne
)- 如果已有实例正在运行,等待它们完成
- 如果没有其他实例正在运行,则继续更新
- 释放互斥锁
我想知道的是最后一步。如果一个特定的应用程序实例创建了互斥锁,那么我认为该实例也关闭互斥锁是安全的;但是,我不确定这会对其他正在等待互斥锁的应用程序实例做什么。
更安全的选择似乎是让每个应用程序简单地释放互斥锁;然而,我不知道在这种情况下互斥是否会被销毁?private const string _mutexName = "NinjaMutexAwesomePants";
private static int _threadId;
void Main()
{
Task.Factory.StartNew(AcquireMutex);
Task.Factory.StartNew(AcquireMutex);
Task.Factory.StartNew(AcquireMutex);
}
void Trace(int threadId, string text, params object[] args)
{
var trace = String.Concat(
String.Format("{0:hh:mm:ss.ffff} T{1}: ", DateTime.Now, threadId),
String.Format(text, args));
Console.WriteLine(trace);
}
void AcquireMutex()
{
var threadId = Interlocked.Increment(ref _threadId);
Trace(threadId, "Started!");
bool createdNew;
var mutex = new Mutex(false, _mutexName, out createdNew);
if (createdNew)
Trace(threadId, "I am the creator!");
else
Trace(threadId, "I did not create the mutex.");
try
{
var isOwner = mutex.WaitOne(TimeSpan.FromSeconds(5));
if (isOwner)
Trace(threadId, "I am the owner of the mutex!");
else
Trace(threadId, "I couldn't acquire the mutex.");
if (isOwner)
{
Thread.Sleep(TimeSpan.FromSeconds(1));
if (createdNew)
mutex.Close();
else
mutex.ReleaseMutex();
Trace(threadId, "I have released the mutex.");
}
}
catch (Exception ex)
{
Trace(threadId, "{0}: {1}", ex.GetType().Name, ex.Message);
}
}
然而,这并没有真正让我明白。看起来,总是使用ReleaseMutex
是最安全的选择(而不是调用Close
),然而,这似乎也像互斥锁永远不会关闭,即使所有线程都释放了互斥锁。实际上,在上面的代码中——如果创建线程也关闭了互斥锁,那么消费者线程永远无法获得它。
所以,我的问题是双重的:
- 在这种情况下,获取/释放互斥锁的最佳策略是什么?
- 如果我只使用
ReleaseMutex
,互斥锁在所有线程释放它后关闭自己吗?
我建议为此目的实现IDisposable
class Updater : IDisposable
{
private readonly Mutex _mutex;
public Updater(string mutexName)
{
bool createdNew;
_mutex = new Mutex(false, mutexName, out createdNew);
if (!_mutex.WaitOne(TimeSpan.FromSeconds(5)) throw new Exception("I could not acquire mutex");
}
public void Update()
{
// Perform the update
}
public void Dispose()
{
_mutex.ReleaseMutex();
_mutex.Close();
}
}
using (var updater = new Updater("NinjaMutexAwesomePants"))
{
updater.Update();
}