Application.Invoke 不需要 需要替换(至少对于我正在使用的版本)。这是一个误解。 Application.Inoke 只是简单地转过身,将一个委托添加到 GLib.Timeout,超时设置为 0,并返回“false”,因此只触发一次。
我没有摆脱 Application.Invoke,而是试图找出为什么我的代表在使用 Application.Invoke 而没有 Appliation.Run 或 Application.Init 时没有触发。请记住,我已经开始了自己的 GLib.MainLoop。
事实证明,应用程序的静态构造函数调用 GLib.Thread.Init(),这基本上是一个定时炸弹。 GLib 的文档指出,使用多个线程时必须调用 GLib.Thread.Init,并且如果 曾经 调用过 GLib.Thread.Init,则必须在使用任何其他 GLib 之前调用它。
因此,在我正在使用的代码中,我们在 Application.Init 之后,但在 Application.Run 之前以及对 Application.Invoke 的任何调用之前,向 GLib.Timeout 添加了一个委托。这意味着我们是安全的,因为 Application.Init 将调用 Application 的静态构造函数,因此调用 GLib.Thread.Init。这很好。但是,当我们删除 Application.Init 并首先调用 Timeout.Add 时,尚未调用 Thread.Init。这意味着如果我们稍后调用 Thread.Init,线程、超时、委托等会阻塞。
果然,Application.Invoke 或 Application.Run 会调用 Application 的静态构造函数,而后者又会调用 GLib.Thread.Init。这导致了问题。
TLDR;
长话短说,确保在应用程序代码中使用 Timeout.Add 之前调用应用程序的静态构造函数。不要手动调用 Glib.Thread.Init,因为在 Mono 上调用两次会导致应用崩溃。
没关系:
Application.Init();
Timeout.Add(0, delegate { return false; });
Application.Invoke(delegate { Console.WriteLine("Hey"); });
Application.Run();
这会毁了你的生活:
// Application.Init();
Timeout.Add(1000, delegate { return false; });
Application.Invoke(delegate { Console.WriteLine("Hey"); });
new MainLoop().Run();
//Application.Run();
但这很好:
// Application.Init();
Application.Invoke(delegate {});
Timeout.Add(1000, delegate { return false; });
Application.Invoke(delegate { Console.WriteLine("Hey"); });
new MainLoop().Run();
//Application.Run();