Re: GTK+ app hang on win32



win32 doesn't support multiple threads in this way and in fact it is not safe to do this in linux either. You should use a GAsyncQueue to notify the main thread, which perhaps has a timeout function listening for such requests or better makes use of GSource. I know there was discussion about this on the list earlier this year. But incase that has become
difficult to find here's example I created.


-todd

Dave Andruczyk wrote:

I've gotten my application to run on windows (Was natively linux) and have hit
several problems...

1.  My app pops up a dialog window in the case of a problem. (i.e. can't talk
to a remote device).  in linux this works perfectly,  in windows it pops up a
blank window and the cursor changes to an hourglass when that window has the
focus

2. As my app is running, it uses glade to load various tabs into a global
gtk_notebook. after each glade file is processed, it tries to call
gtk_notebook_append_page() and under win32 this call HANGS indefinitely, task
manager reports 0% cpu usage, so it doesn't appear to be stuck in a race)

NOTE regarding #2.  the tab loading is run from within a thread that is wrapped
by calls to gdk_threads_enter() and gdk_threads_leave().  This works flawlessly
on linux, freebsd and OS-X,  but hangs at the above location on windows (Win2k
SP4).  Is this a GTK+ bug in the gtk_notebook or glib itself on win32?

I'm using gtk-win32-2.4.14-rc1, and libglade-2.4.0 from the
gladewin32.sourceforge.net site.






=====
Dave J. Andruczyk


                
__________________________________ Do you Yahoo!? The all-new My Yahoo! - What will yours do? http://my.yahoo.com _______________________________________________
gtk-app-devel-list mailing list
gtk-app-devel-list gnome org
http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list

#include <gtk/gtk.h>
#include <glade/glade.h>

typedef struct _Prog Prog;

struct _Prog{
        GSource source;
        gint counter;
        gint update;

        /* do not access from thread */
        GtkWidget *progress;
};

static gboolean run_prepare( GSource *src, gint *timeout );
static gboolean run_check( GSource *src );
static gboolean run_dispatch( GSource *src, GSourceFunc callback, gpointer usr_data );
static gboolean run_callback( gpointer data );
static void dolotsofwork( Prog *prog );
static void reset( GtkWidget *button, Prog *prog );
static void shutdown( GtkObject *obj, Prog *prog )
{
        gint *count  = &(prog->counter);
        gint *notify = &(prog->update);

        g_atomic_int_exchange_and_add( count, 100 + ( g_atomic_int_get( count ) * -1 ) );
        g_atomic_int_compare_and_exchange( notify, 0, 1 );

        gtk_main_quit();
}

int main( int argc, char **argv )
{
        GSourceFuncs funcs = { run_prepare, run_check, run_dispatch, 0 };
        Prog *src = (Prog*)g_source_new( &funcs, sizeof( Prog ) );
        GladeXML *xml;
        GThread *tid;
        GError *error = 0;

        src->counter = 0;
        src->update = 0;

        gtk_rc_add_default_file( "gtkrc" );
        g_thread_init(NULL);
        gtk_init( &argc, &argv );

        xml = glade_xml_new( "events.glade", 0, 0 );
  if( xml == 0 ){
    return 1;
  }

        src->progress = glade_xml_get_widget( xml, "progressbar1" );

        glade_xml_signal_connect_data( xml, "on_window1_destroy", G_CALLBACK( shutdown ), src );
        glade_xml_signal_connect_data( xml, "on_button1_clicked", G_CALLBACK( reset ), src );

        g_object_unref( xml );

        g_source_set_callback( (GSource*)src, (GSourceFunc)run_callback, src, 0 );
        g_source_attach( (GSource*)src, g_main_context_default() );

        tid = g_thread_create( (GThreadFunc)dolotsofwork, src, FALSE, &error );
        if( !tid || error ){
                g_printerr( "Error creating thread: %s\n", error->message );
                g_error_free( error );
                return 1;
        }

        gtk_main();

        g_source_destroy( (GSource*)src );

        return 0;
}
static void 
reset( GtkWidget *button, Prog *prog )
{
        gint *count  = &(prog->counter);
        gint *notify = &(prog->update);

        g_atomic_int_exchange_and_add( count, g_atomic_int_get( count ) * -1 );
        g_atomic_int_compare_and_exchange( notify, 0, 1 );
}

static void 
dolotsofwork( Prog *prog )
{
        guint i;
        gint *counter = &prog->counter;
        gint *notify = &prog->update;
        for( i = 0; i < 100; i = g_atomic_int_exchange_and_add( counter, 1 ) ){
                g_atomic_int_compare_and_exchange( notify, 0, 1 );
                g_usleep( 100000 );
        }
}

static gboolean 
run_callback( gpointer data )
{
        Prog *prog = (Prog*)data;
        gint *tmp = &(prog->counter);
        gint *notify = &(prog->update);
        gdouble counter = (gdouble)g_atomic_int_get( tmp );
        GtkProgressBar *progress = GTK_PROGRESS_BAR( prog->progress );
        gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR( progress ), counter / 100.0 );
        g_atomic_int_compare_and_exchange( notify, 1, 0 );

  if( counter >= 99.999 )
    g_print( "done\n" );
        return counter < 99.999;
}

static gboolean 
run_prepare( GSource *src, gint *timeout )
{
        *timeout = 10;
        return run_check( src );
        // return true if ready
}
static gboolean 
run_check( GSource *src )
{
        Prog *prog = (Prog*)src;
        gint *tmp = &(prog->update);
        // return true if ready
        return g_atomic_int_get( tmp );
        
}
static gboolean 
run_dispatch( GSource *src, GSourceFunc callback, gpointer usr_data )
{
        // call the callback
        //
        // return false if done
  return callback( usr_data );
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]