【问题标题】:mutex is not working when it release in C# but debug is working [duplicate]互斥锁在 C# 中发布时不工作,但调试工作 [重复]
【发布时间】:2020-12-28 01:04:14
【问题描述】:

我希望程序在已经运行时不再运行。

当我使用调试模式时代码可以工作,但在发布时无法正常工作。

代码如下。

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        string mtxName = "test mutex";
        Mutex mtx = new Mutex(true, mtxName);
        TimeSpan tsWait = new TimeSpan(0, 0, 1);
        bool success = mtx.WaitOne(tsWait);
        if (!success)
        {
            MessageBox.Show("is running.");
            return;
        }

        Application.Run(new Form1());

【问题讨论】:

  • 在副本中查看(当前)第二个(通过投票)答案。你需要一个全局互斥体。
  • @runRyan 我复制了您的代码示例,尝试在 Release 配置中重现该问题(同时启动 2 个应用程序),但无法实现。我为 AnyCPU、x86 和 x64 编译 - 没有区别,我总是收到“正在运行”消息。请在问题中添加更多详细信息 - 您使用什么 .NET 框架以及 CLR version 是什么(我尝试使用 .NET4.6 和 CLR 4.0.30319.42000)
  • @fenixil 我想你会写多次关于 application.run(new form1());对吗??
  • 总之,我的主要问题是为什么当我使用调试模式和发布模式时它会以不同的方式发生。
  • @runRyan,我不关注您关于 application.run 多次的问题,请详细说明。正如 RossBush 指出的那样,问题在于您没有对互斥锁的引用,因此它被 GC 释放和销毁。原因,为什么一切都在调试模式下工作,是因为编译器生成“更安全”的代码并在线程堆栈中保存对互斥体的引用。在 Release 中,这不会发生,因为代码更加优化。

标签: c# mutex


【解决方案1】:

为什么不使用互斥锁?

namespace My.Program
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            bool exclusive;
            System.Threading.Mutex appMutex = new System.Threading.Mutex(true, "My.Program", out exclusive);
            if (!exclusive)
            {
                MessageBox.Show("Another instance of My Program is already running.","My Program",MessageBoxButtons.OK,MessageBoxIcon.Exclamation );
                return;
            }
            Application.SetCompatibleTextRenderingDefault(false);
            GC.KeepAlive(appMutex);
            Application.Run(new frmMyMainForm());
        }
    }
}

【讨论】:

  • “为什么不使用互斥锁?” -- OP 的代码确实使用Mutex。您的问题如何回答原始问题?
  • 也许在同一个进程中没有任何东西指向你的 Mutex,GC 会执行它。也许你错过了 -> GC.KeepAlive(appMutex);
  • @RossBush 哦,谢谢你的回复,我明白了,但是我仍然有一个问题,为什么当我使用调试模式时互斥锁工作?
  • 还有一件事,是不是和“宣布全局互斥”和“GC.KeepAlive(appMutex)”的机制一样???
  • @RossBush, Application.Run 是一个阻塞调用,因此您的解决方案之所以有效,只是因为堆栈中存在对 appMutex 的引用,可以防止它被破坏。这可能会使读者感到困惑,因此要么将其移至 Application.Run 之上,要么在 Main() 存在时显式释放互斥锁,例如将其包装到使用中。另外,我强烈建议您在答案中添加详细信息,为什么该问题的解决方案不够(不幸的是,问题已关闭,因此我无法附加 idasm diff)
【解决方案2】:

我认为您可能没有将 Mutex 用于其预期目的,互斥锁用于控制对资源的访问以使其“线程安全”,也许您应该查看进程列表。

Process myProcess = Process.GetCurrentProcess();
var processExists = Process.GetProcesses().Any(
    p => p.ProcessName.Equals(myProcess.ProcessName) 
    && p.Id != myProcess.Id);
if (processExists)
    return;

但是如果你真的想使用互斥锁,试试

    static Mutex mutex = new Mutex(true, "Something unique here");

    [STAThread]
    static void Main()
    {
        if (mutex.WaitOne(TimeSpan.Zero, true))
        {
            try
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
            finally
            {
                mutex.ReleaseMutex();
            }
        }
        else
        {
            MessageBox.Show("is running.");
        }
    }

【讨论】:

  • “互斥锁用于控制对资源的访问” -- 全局互斥锁通常用于控制对正在运行的程序本身的“资源”的访问,根据这个问题的实际重复。您对使用 Process 类的建议实际上很差,主要是因为竞争条件(两个相同的进程可以尝试同时启动,通过相同的代码路径建立没有实例已经在运行,导致两个实例保持运行)。 保证只有一个实例不是一种可靠的方法。
  • 从技术上讲,进程检查可以允许进程共存,这在技术上是正确的,因为要发生这种情况,两个进程之间必须有一个非常小的余量。为什么投反对票,我为 Mutex 方法提供了一个可行的解决方案
  • @Xavier,您的答案复制粘贴了解决方案,但与最初的问题无关 - 为什么代码在调试模式下工作,而不是在发布模式下工作。这就是投反对票的原因。
猜你喜欢
  • 1970-01-01
  • 2012-09-04
  • 1970-01-01
  • 2020-09-16
  • 1970-01-01
  • 1970-01-01
  • 2018-03-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多