2009-02-03 20 views
5

estoy tratando de hacer una aplicación multiplataforma C# usando C#, mono/GTK # en Linux y .NET/GTK # en Windows, sin embargo, la secuencia de arranque parece que tenga que ser un poco diferente bajo las dos plataformas:Crossplatform threading y GTK #, no funciona (correctamente)?

en Linux:

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

en Windows:

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

Ambos requieren que se haga de esa manera: Windows se queja de g_thread_init() no ser llamado con el código de Linux y Linux se queja de que ya se están llamado con el código de Windows. Aparte de esto, todo funciona maravillosamente.

Mi primer intento de una "solución" se parecía a:

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

Pero incluso esta solución no funciona desordenado; el error proviene de GTK +, código no administrado, por lo que no se puede capturar. ¿Alguien tiene ideas brillantes sobre la causa del problema y cómo solucionarlo? O, en su defecto, tener ideas brillantes sobre cómo detectar cuál debería llamarse en tiempo de ejecución.

Respuesta

8

Gtk + en Win32 no admite correctamente el subprocesamiento. Debe hacer todas sus llamadas a la GUI desde el mismo hilo que llamó Gtk.Main().

No es realmente tan malo como parece. Hay un truco que puede usar para enviar funciones al hilo principal. Simplemente use GLib.Idle.Add() desde cualquier subproceso y la función se llamará en breve en el mismo subproceso en el que se está ejecutando el bucle principal. Solo recuerde devolver falso en la función del controlador inactivo, o continuará ejecutándose para siempre.

Si sigue y utiliza las técnicas anteriores, ni siquiera necesita llamar a Gdk.Threads.Init() en absoluto.

+0

Tiene derecho a Johan: realmente no necesita llamar a las funciones de GDK desde varios hilos, y es una mala idea hacerlo de todos modos (Winforms y WPF ni siquiera le permiten hacerlo) –

+0

Gracias por hacer un esfuerzo adicional y buscando las # llamadas GTK :) –

+0

Woho! Gracias por los 300 puntos! –

0

Umm, ¿ha intentado decorar su método principal con el atributo [STAThread]?

p. Ej.

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

De no ser así se podría utilizar la compilación condicional al igual que ...

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

Tengo la impresión de que STAThread solo afecta a COM, por lo que esto no significa nada en este caso. –

2

no estoy seguro de si esto funciona en Mono, pero se puede utilizar la clase de entorno para determinar qué sistema operativo del programa se está ejecutando

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... 

La enumeración PlatformID contiene algo más que Windows y Unix sin embargo, por lo que debe comprobar si hay otros valores.

1

En realidad, esto podría ser un error en los enlaces C# para GDK o su versión de GDK. De acuerdo con la documentación para gdk\_threads\_init(), g\_thread\_init() tiene que ser llamado primero, y la documentación de GTK # dice lo mismo:

GLib.Thread.Init() has to be called before Gdk.Threads.Init() .

En mi máquina Linux (con GDK 2.14.4), un programa C que llama gdk\_threads\_init() sin haber llamado g\_thread\_init() imprime un mensaje de error y termina con un error. ¿Se ha asegurado de tener la misma versión GDK tanto en Linux como en Windows, y que la versión en Linux (si es diferente de la versión de Windows) también requiere la llamada al g\_thread\_init(), o si es algo que se ha cambiado entre los dos versiones. Por último, compruebe que este programa termina con un error:

#include <gdk/gdk.h> 

int main(int argc, char **argv) { 
    gdk_threads_init(); 

    return 0; 
}

compilarlo con gcc -o test `pkg-config --cflags --libs gdk-2.0` test.c
(suponiendo que haya guardado como test.c.)

Si ese programa termina con un error, es un error en su biblioteca GDK #.
Si no es así, es un error en su versión de GDK.

+0

No es que no lo llamen, se lo está llamando, simplemente se lo llama como parte del contenedor en Linux, y no se lo llama como parte del contenedor en Windows. Estoy probando con las mismas versiones de GTK # en ambos, pero no estoy seguro acerca de las versiones de gtk +. –

+0

Confirmado por su pequeña prueba, la diferencia está definitivamente en GTK #, pero estoy usando la misma versión entre Linux y Windows. –

+0

He intentado buscar en las fuentes de GTK #, pero no puedo encontrar ningún lugar obvio que Gdk.Threads.Init() llame a g \ _thread \ _init(), así que creo que su próxima parada deberían ser los desarrolladores de GTK # 'lista de correo o foro, pero esto me parece un poco extraño. – arnsholt

Cuestiones relacionadas