原来只是打算实现一个进程互斥的功能,而.NET似乎没有内置,所以决定调Windows API自己写。原来简单的几句代码,加上了Exception Handling和Dispose Pattern后,居然搞出了近一百行代码,还没怎么写注释。

/// <summary>
/// Process level simple mutex class. By Sunmast.
/// </summary>
/// <remarks>
/// Always avoid duplicate mutex names.
/// </remarks>
class ProcessMutex : IDisposable
{
    [DllImport("Kernel32.dll")]
    static extern IntPtr CreateMutex(IntPtr lpMutexAttributes, bool bInitialOwner, string lpName);
    [DllImport("Kernel32.dll")]
    static extern bool ReleaseMutex(IntPtr hMutex);
    [DllImport("Kernel32.dll")]
    static extern uint WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);

    const uint WAIT_ABANDONED = 0x00000080;
    const uint WAIT_OBJECT_0 = 0x00000000;
    const uint WAIT_TIMEOUT = 0x00000102;
    const uint WAIT_FAILED = 0xFFFFFFFF;
    const int MAX_PATH = 260;

    IntPtr hMutex;
    bool disposed;

    public ProcessMutex(string mutexName)
        : this(mutexName, int.MaxValue)
    {
    }

    public ProcessMutex(string mutexName, int timeout)
    {
        if (mutexName == null)
        {
            throw new ArgumentNullException("mutexName");
        }
        if (mutexName.Length > MAX_PATH)
        {
            throw new PathTooLongException("The name is limited to MAX_PATH characters.");
        }
        hMutex = CreateMutex(IntPtr.Zero, false, mutexName);
        if (hMutex == IntPtr.Zero)
        {
            throw new InvalidOperationException("Mutex creation failed.");
        }
        uint waitResult = WaitForSingleObject(hMutex, timeout);
        switch (waitResult)
        {
            case WAIT_TIMEOUT:
                throw new TimeoutException("Cannot get mutex ownership due to time-out.");
            case WAIT_OBJECT_0:
                break;
            case WAIT_ABANDONED:
                throw new InvalidOperationException(
                    "The specified object is a mutex object that was not released by the " +
                    "thread that owned the mutex object before the owning thread terminated.");
            case WAIT_FAILED:
                throw new InvalidOperationException("Function failue.");
            default:
                break;
        }
    }

    ~ProcessMutex()
    {
        Dispose(false);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Nothing to do.
            }
            ReleaseMutex(hMutex);
            disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

其用法有点类似C#的lock关键字,可以定义一个scope,例:

using (new ProcessMutex("MUTEX_TEST"))
{
    Console.WriteLine("Wait for ENTER key pressed.");
    Console.ReadLine();
}

看来白忙了,.NET已经内置了这个功能了。原来一直以为所有的WaitHandle都是线程级别的...