互斥体本身是否靠近?

时间:2014-03-20 01:57:36

标签: c# multithreading mutex

我尝试在适当的时候使用ReleaseMutex,以及何时适合使用Close

我们(有效地)正在编写一个"自动更新程序"在C#中键入应用程序。用户可以同时运行自动更新程序的多个实例,但是每个实例必须等待其他实例在完成之前完成。如此有效,申请流程如下:

  • 启动更新程序,创建互斥锁(new Mutex(false, "MyMutex", out isCreator)
  • 检查现有的正在运行的实例(Mutex.WaitOne
    • 如果有现有实例正在运行,请等待它们完成
    • 如果没有其他实例正在运行,请继续进行更新
  • 释放互斥锁

这是我想知道的最后一步。如果特定的应用程序实例创建了 Mutex,那么我认为该实例也可以安全地关闭 Mutex;但是,我不确定这会对那些等待该Mutex的其他应用程序实例做些什么。

更安全的选择似乎是让每个应用程序只需释放互斥锁;但是,在这种情况下,我不知道互斥锁是否会被破坏?

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. 在这种情况下,获取/发布互斥锁的最佳策略是什么?
  2. 如果我只使用ReleaseMutex,那么在所有线程释放后,互斥锁是否会自行关闭?

1 个答案:

答案 0 :(得分:1)

我建议为此目的实施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();
}