跨平台线程和GTK#,无法正常工作?

我正在尝试使用C#,Linux上的单声道/ GTK#和Windows上的.NET / GTK#创建跨平台C#应用程序,但是在两个平台下启动顺序似乎需要略有不同:

在Linux下:

public static void Main (string[] args) { Gdk.Threads.Init (); // etc... 

在Windows下:

 public static void Main (string[] args) { Glib.Thread.Init (); Gdk.Threads.Init (); // etc... 

两者都要求以这种方式完成:Windows抱怨g_thread_init()没有使用linux代码调用,并且linux抱怨已经使用Windows代码调用它。 除此之外,这一切都非常有效。

我对“解决方案”的第一次尝试看起来像:

 public static void Main (string[] args) { try { Gdk.Threads.Init (); } catch (Exception) { GLib.Thread.Init (); Gdk.Threads.Init (); } // etc... 

但即便是这种凌乱的解决方案也行不通; 错误来自GTK +,非托管代码,因此无法捕获。 有没有人对问题的原因有什么好主意,以及如何解决它? 或者,如果没有这个,那么如何检测应该在运行时调用哪一个?

Win32上的Gtk +不能正确支持线程。 您需要从与调用Gtk.Main()相同的线程执行所有GUI调用。

它实际上并不像听起来那么糟糕。 您可以使用一种技巧将函数分派给主线程。 只需从任何线程使用GLib.Idle.Add(),函数将在主循环运行的同一个线程中调用。只需记住在空闲处理程序函数中返回false,否则它将继续运行。

如果您遵循并使用上述技术,您根本不需要调用Gdk.Threads.Init()。

我不确定这是否适用于Mono,但您可以使用Environment类来确定运行该程序的操作系统。

 public static void Main (string[] args) { PlatformID platform = Environment.OSVersion.Platform; if (platform == PlatformID.Win32NT || platform == PlatformID.Win32S || platform == PlatformID.Win32Windows) Glib.Thread.Init(); else if (platform != PlatformID.Unix) throw new NotSupportedException("The program is not supported on this platform"); Gdk.Threads.Init(); // etc... 

PlatformID枚举不仅仅包含Windows和Unix,因此您应该检查其他值。

实际上,这可能是GDK的C#绑定或您的GDK版本中的错误。 根据gdk\_threads\_init(), g\_thread\_init()的文档,必须首先调用gdk\_threads\_init(), g\_thread\_init() ,并且GTK#文档说的相同:

必须在Gdk.Threads.Init()之前调用Gdk.Threads.Init()

在我的Linux机器上(使用GDK 2.14.4),在没有调用g\_thread\_init()情况下调用gdk\_threads\_init()的C程序会输出错误消息并以错误终止。 您是否确保在Linux和Windows上都拥有相同的GDK版本,并且Linux上的版本(如果它与Windows版本不同)也需要调用g\_thread\_init() ,或者它是否为已在两个版本之间进行了更改。 最后,检查此程序是否因错误而终止:

 #include  int main(int argc, char **argv) { gdk_threads_init(); return 0; } 

gcc -o test `pkg-config --cflags --libs gdk-2.0` test.c编译它gcc -o test `pkg-config --cflags --libs gdk-2.0` test.c
(假设您已将其保存为test.c.)

如果该程序因错误而终止,则这是您的GDK#库中的错误。
如果没有,那就是你的GDK版本中的一个错误。

嗯,你试过用[STAThread]属性装饰你的Main方法吗?

例如

 #if !Mono //or whatever [STAThread] #endif public static void Main (string[] args) { Gdk.Threads.Init (); ... } 

如果没有你可以像这样使用条件编译……

 public static void Main (string[] args) { Gdk.Threads.Init (); #if !Mono //or whatever Gdk.Threads.Init (); #endif ... }