互斥对象会自己关闭吗?

本文关键字:自己 对象 | 更新日期: 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),然而,这似乎也像互斥锁永远不会关闭,即使所有线程都释放了互斥锁。实际上,在上面的代码中——如果创建线程也关闭了互斥锁,那么消费者线程永远无法获得它。

所以,我的问题是双重的:

    在这种情况下,获取/释放互斥锁的最佳策略是什么?
  1. 如果我只使用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();
}