【问题标题】:Displaying a form locks up mono显示表单会锁定单声道
【发布时间】:2011-08-11 09:43:44
【问题描述】:

我有一个用 c# 编写并在 Mac 上使用“mono myapp.exe”执行的单声道应用程序

从项目属性查看时,该应用程序本身是一个“Windows 应用程序”,但它并不总是显示一个窗口。在program.cs中,有一个静态的Main:

static void Main(string[] args) {
    UserClient client = new UserClient();
    client.Start(args);
}

public class UserClient {
    public void Start(string[] args) {
          // Talk to server, listen for instructions, etc.
          ....
          // Launch the "Stay Alive" thread
          // Just a thread that Sleeps/Loops watching for an exit command; mainly used to keep the process alive
    }
}

在 UserClient 的 Start 方法中,有一段代码可以持续监控服务器,并为其提供执行操作的指令。它所做的其中一件事是可选地使用 Windows 窗体显示一条消息。

当服务器指示进程显示消息时,它会实例化一个表单,使用frm.ShowDialog() 显示它,然后在 30 秒后,表单上的计时器运行 Close(),然后 frm 被释放。但是,当这种情况发生时,在我的 Mac 上,我会看到一个应用程序标题栏显示“单声道”,并且在我的停靠栏上看到一个单声道应用程序的新图标。大约 2 分钟后,活动监视器中的单声道进程显示“无响应”。这最终将阻止用户注销、关闭等(因为 Mac OS 无法优雅地终止单声道)。

另一方面...如果服务器从不告诉进程显示该表单,那么一切运行良好且花花公子:停靠图标永远不会出现(这很好!),单声道标题栏永远不会出现,单声道进程继续愉快地运行,不会阻止系统关闭或重新启动。

任何人都经历过这种情况或对造成这种情况的原因有想法?我的猜测是,它是由表单创建的一个新的 GUI 线程,它永远不会被关闭并且以某种方式导致锁定,尽管我不确定如何处理它。

感谢您的任何建议。

更新:

这里有一些代码可以轻松重现并查看这种情况。我意识到这似乎有点“不标准”。话虽如此,以下内容在 Windows 环境中完美运行,并提供了在任务区域中不显示图标的预期结果,除非显示消息。目前,使用 Application.Run 并简单地执行 frm.ShowDialog() 会产生完全相同的结果。

最后,我们需要的是能够显示表单,然后从 Dock 中销毁表单和任何关联的图标。我怀疑 GUI 正在启动一个从未被处理过的线程,这就是为什么停靠图标仍然存在的原因。有没有办法确保 GUI 线程得到处理?

static class Program {
    static void Main() {            
        StartupClass s = new StartupClass();
        s.start();
    }
}

public class StartupClass {
    Thread stayAliveThread;

    public void start() {
        // Stay alive thread
        stayAliveThread = new Thread(stayAliveLoop);
        stayAliveThread.Start();

        // This shows a form and would normally be used to display temporary and brief messages to the user. Close the message and you'll see the undesired functionality. 
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
        Application.Exit();
        Application.ExitThread();
    }

    /// <summary>
    /// Keep the app alive.
    /// </summary>
    private void stayAliveLoop() {
        while (true) {
            Thread.Sleep(10000);
            // In the real project this method monitors the server and performs other tasks, only sometimes displaying a message.
        }
    }
}

【问题讨论】:

  • 你真的应该能够从我在那里看到的文本描述中制作一个非常简短的最小示例。 (为什么?这将有助于从关键部分中筛选出愚蠢/琐碎的建议;如果有太多未知数,Stacko 常规人群倾向于学会闭嘴:它只会导致风格中的冗长评论线程: '是的,我知道;但它仍然不起作用';'哦,那不适用,因为我用 X 方式解决了它;'等等。)一些代码消除了噪音跨度>

标签: c# macos mono


【解决方案1】:

我觉得我错过了几件事。最值得注意的是

 [STAThread]
 static void Main(string[] args) { //....

另请参阅此答案:Windows Forms and ShowDialog problem

【讨论】:

    【解决方案2】:

    我看不到为窗口应用程序初始化消息循环之类的东西。 IE。在 Windows 窗体中类似于 Application.Run()。如果您没有它,难怪应用程序会冻结。无论如何,如评论中所述,发布更多代码可能会有所帮助。

    【讨论】:

    • 确实,没有调用 Application.Run()。至少在 Windows 中,这给了我们想要的效果,让应用“感觉”像一个隐藏的进程,并且只在显示消息时显示(在任务栏中)。
    • 我不确定您的描述,但您可能直接从另一个线程调用 ShowDialog 和 Close。您不应该这样做 - 使用 Invoke 或 BeginInvoke。
    【解决方案3】:

    最后,我无法解决这个问题。我创建了一个进程来启动另一个显示消息表单的应用程序。不是真正的答案,而是我必须采用的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-17
      • 2012-11-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多