在 dotnet 核心中,如何确保我的应用程序只有一份副本是 运行?

In dotnet core how can I ensure only one copy of my application is running?

我以前做过这样的事情

private static bool AlreadyRunning()
{
    var processes = Process.GetProcesses();
    var currentProc = Process.GetCurrentProcess();
    logger.Info($"Current proccess: {currentProc.ProcessName}");
    foreach (var process in processes)
    {
        if (currentProc.ProcessName == process.ProcessName && currentProc.Id != process.Id)
        {
            logger.Info($"Another instance of this process is already running: {process.Id}");
            return true;
        }
    }
    return false;
}

效果很好。在新的 dotnet 核心世界中,所有东西都有一个 dotnet 的进程名称,所以我一次只能 运行 一个 dotnet 应用程序!不是我想要的 :D

在 dotnet 中是否有理想的方法来做到这一点?我看到建议的互斥体,但我不确定我是否理解 运行 在 windows 机器以外的其他系统上可能出现的缺点或错误状态。

.NET Core 现在支持全局命名互斥锁。来自 PR description,添加了该功能:

  • On systems that support thread process-shared robust recursive mutexes, they will be used
  • On other systems, file locks are used. File locks, unfortunately, don't have a timeout in the blocking wait call, and I didn't find any other sync object with a timed wait with the necessary properties, so polling is done for timed waits.

此外,Named mutex not supported on Unix 问题中有一个关于互斥体名称的有用说明,应该使用:

By default, names have session scope and sessions are more granular on Unix (each terminal gets its own session). Try adding a "Global" prefix to the name minus the quotes.

最后我使用了一个互斥体,它看起来没问题。

我从这里获取代码 What is a good pattern for using a Global Mutex in C#?

我使用的核心版本似乎没有一些安全设置的东西所以我就把它删除了。我相信它会没事的。 (new Mutex只需要3个参数)

private static void Main(string[] args)
{
    LogManager.Configuration = new XmlLoggingConfiguration("nlog.config");
    logger = LogManager.GetLogger("console");
    logger.Info("Trying to start");

    const string mutexId = @"Global\{{guid-guid-guid-guid-guid}}";

    bool createdNew;
    using (var mutex = new Mutex(false, mutexId, out createdNew))
    {
        var hasHandle = false;
        try
        {
            try
            {
                hasHandle = mutex.WaitOne(5000, false);
                if (!hasHandle)
                {
                    logger.Error("Timeout waiting for exclusive access");
                    throw new TimeoutException("Timeout waiting for exclusive access");
                }
            }
            catch (AbandonedMutexException)
            {
                hasHandle = true;
            }

            // Perform your work here.
            PerformWorkHere();
        }
        finally
        {
            if (hasHandle)
            {
                mutex.ReleaseMutex();
            }
        }
    }
}