C# GTK#应用程序。调用不工作

C# GTK#应用程序。调用不工作,c#,.net,multithreading,mono,gtk,C#,.net,Multithreading,Mono,Gtk,我正在开发一个通过使用application.Invoke的许多库与GTK紧密绑定的应用程序。不幸的是,我们正在将应用程序(服务器类型的应用程序)移植到一个没有窗口管理器的系统上,因此当我们初始化GTK时,它当前会崩溃 如果不调用Application.Init,Application.Invoke似乎无法工作,即使在运行我自己的GLib.MainLoop时也是如此 我正在寻找Application.Invoke的合适替代品。我应该如何在应用程序使用的库中替换Application.Invoke

我正在开发一个通过使用application.Invoke的许多库与GTK紧密绑定的应用程序。不幸的是,我们正在将应用程序(服务器类型的应用程序)移植到一个没有窗口管理器的系统上,因此当我们初始化GTK时,它当前会崩溃

如果不调用Application.Init,Application.Invoke似乎无法工作,即使在运行我自己的GLib.MainLoop时也是如此

我正在寻找Application.Invoke的合适替代品。我应该如何在应用程序使用的库中替换Application.Invoke,以便消除对GTK的依赖


注意:我已经提出了一个重构方案,将GUI从应用程序和域代码中删除,并将其移动到视图中,但现在已经被否决了。我基本上是想让它在没有窗口管理器的系统上运行。

Application.Invoke基本上是通过保留要运行的委托列表来工作的

每次GTK主循环迭代时,它都会检查这个列表并执行它找到的任何内容。听起来你需要一个像这样循环的背景线程

也就是说,我无法想象在非图形应用程序上如何或为什么需要这种循环调用,只要直接在那里调用,您可能也会得到很好的服务。例如:

public static class Application {

   public static void Invoke ( EventHandler dothis ) {
      if ( dothis != null ){ 
         dothis( null, null ); }
   }
}

Invoke基本上是通过保存要运行的委托列表来工作的

每次GTK主循环迭代时,它都会检查这个列表并执行它找到的任何内容。听起来你需要一个像这样循环的背景线程

也就是说,我无法想象在非图形应用程序上如何或为什么需要这种循环调用,只要直接在那里调用,您可能也会得到很好的服务。例如:

public static class Application {

   public static void Invoke ( EventHandler dothis ) {
      if ( dothis != null ){ 
         dothis( null, null ); }
   }
}

如果您希望异步处理不需要在特定线程上进行,请查看。这种方法的主要问题是您必须自己确保线程安全

如果确实需要在主线程上执行此操作,则需要创建一个委托列表,以便在主线程上定期调用和轮询该列表(或等待向其发布内容):

使用System.Collections.Generic;
使用系统线程;
班长{
队列操作=新队列();
ManualResetEvent\u事件=新的ManualResetEvent(错误);
公共无效调用(操作)
{
锁定(操作){
动作。排队(动作);
_event.Set();
}
}
公众投票()
{
Action=null;
锁定(操作){
如果(actions.Count>0){
action=actions.Dequeue();
}
}
如果(操作!=null)
行动();
}
公共无效等待()
{
Action=null;
while(true){
_event.WaitOne();
锁定(操作){
如果(actions.Count>0){
action=actions.Dequeue();
}否则{
_event.Reset();
}
}
如果(操作!=null)
行动();
}
}
}

如果您希望异步处理不需要在特定线程上进行,请查看。这种方法的主要问题是您必须自己确保线程安全

如果确实需要在主线程上执行此操作,则需要创建一个委托列表,以便在主线程上定期调用和轮询该列表(或等待向其发布内容):

使用System.Collections.Generic;
使用系统线程;
班长{
队列操作=新队列();
ManualResetEvent\u事件=新的ManualResetEvent(错误);
公共无效调用(操作)
{
锁定(操作){
动作。排队(动作);
_event.Set();
}
}
公众投票()
{
Action=null;
锁定(操作){
如果(actions.Count>0){
action=actions.Dequeue();
}
}
如果(操作!=null)
行动();
}
公共无效等待()
{
Action=null;
while(true){
_event.WaitOne();
锁定(操作){
如果(actions.Count>0){
action=actions.Dequeue();
}否则{
_event.Reset();
}
}
如果(操作!=null)
行动();
}
}
}
不需要替换Application.Invoke(至少对于我正在使用的版本)。这是一种误解。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将调用应用程序的静态构造函数,因此调用GLib.Thread.Init。这很好。然而,当我们删除Application.Init并调用Timeout.Add first时,还没有调用Thread.Init。这意味着如果我们稍后调用Thread.Init,线程、超时、委托等都会阻塞

果不其然,Application.Invoke或Application.Run将调用应用程序的静态构造函数,我
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();