GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Sat Dec 20, 2014 5:18 pm

All times are UTC




Post new topic Reply to topic  [ 8 posts ] 
Author Message
 Post subject: g_thread_create - problem
PostPosted: Tue Apr 10, 2012 12:27 pm 
Offline
Familiar Face

Joined: Fri Mar 25, 2011 7:55 am
Posts: 35
Location: romania
Hi,

The code below is working compiled in linux, compiled in win32 under WINE.
Is not working compiled in win32 in VirtualBox Win XP and in Windows XP.
I have no ideea what is wrong.
In VirtualBox Win XP and in Windows XP it hangs after " if ( !pcClass->bStop ) gtk_widget_destroy( pcClass->dialog );" in
"thread" function.

Any help please ?

Thanks !


Code:
typedef class cList cLIST, *pcLIST;
class cList {
protected:
public:
   gboolean   bStop;
   GtkWidget *dialog;
   GtkWidget *cancel;
   GtkWidget *pbar;

   cList( pBOOL pbInitStatus );
   ~cList( void );
};

cLIST::cList( pBOOL pbInitStatus ) {
   bStop = FALSE;
}

cLIST::~cList( void ) {
}

static void *thread( gpointer ptr ) {
   pcLIST pcClass = ( pcLIST )ptr;
   CHAR   szPercent[ 30 ] = "";
   ULONG  ulRows;
   CHAR   szBuffer[ __BUFSIZ + 1 ];
   DOUBLE dbPercent;
   int    i = 0;
   int    k = 1000;

   do {
      dbPercent = (( DOUBLE )( i + 1 ) * 100.0 ) / ( DOUBLE )k;
      sprintf( szPercent, "%.2lf%%", dbPercent );
      gdk_threads_enter();
      gtk_progress_bar_set_text( GTK_PROGRESS_BAR( pcClass->pbar ), szPercent );
      gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR( pcClass->pbar ), ( dbPercent / 100.0 ) );
      gdk_threads_leave();
      g_usleep( 6000 );
   } while (( !pcClass->bStop ) && ( ++i < k ));   
   if ( !pcClass->bStop ) gtk_widget_destroy( pcClass->dialog );
   return( NULL );
}

static void cancel( GtkWidget *widget,
                    gpointer   data ) {
   pcLIST pcClass = ( pcLIST )data;

   pcClass->bStop = TRUE;
   gtk_widget_destroy( pcClass->dialog );
}

void gtkList( GtkWidget *widget,
              gpointer   data ) {
   BOOL   bInitStatus = TRUE;
   pcLIST pcClass     = new cLIST( &bInitStatus );
   
   if ( pcClass != NULL ) {
      GtkWidget *main_vbox;
      GtkWidget *main_hbox;
      GtkWidget *hbox;
      GtkWidget *hseparator;

      pcClass->dialog = gtk_dialog_new();
      gtk_window_set_modal( GTK_WINDOW( pcClass->dialog ), GTK_DIALOG_MODAL );
      gtk_container_set_border_width( GTK_CONTAINER( pcClass->dialog ), 0 );
      gtk_window_set_resizable( GTK_WINDOW( pcClass->dialog ), FALSE );
      gtk_window_set_position( GTK_WINDOW( pcClass->dialog ), GTK_WIN_POS_CENTER );
      gtk_widget_set_size_request( GTK_WIDGET( pcClass->dialog ), 300, 80 );
     
      main_vbox = gtk_vbox_new( FALSE, 0 );
      gtk_container_set_border_width( GTK_CONTAINER( main_vbox ), 0 );
      gtk_container_add( GTK_CONTAINER( GTK_DIALOG( pcClass->dialog )->vbox ), main_vbox );

      hseparator = gtk_hseparator_new();
      gtk_box_pack_start( GTK_BOX( main_vbox ), hseparator, TRUE, TRUE, 0 );

      pcClass->pbar = gtk_progress_bar_new();
      gtk_box_pack_start( GTK_BOX( main_vbox ), pcClass->pbar, FALSE, FALSE, 0 );
      gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR( pcClass->pbar ), 0.0 );
      gtk_progress_bar_set_orientation( GTK_PROGRESS_BAR( pcClass->pbar ), GTK_PROGRESS_LEFT_TO_RIGHT );

      hseparator = gtk_hseparator_new();
      gtk_box_pack_start( GTK_BOX( main_vbox ), hseparator, TRUE, TRUE, 0 );

      hbox = gtk_hbox_new( FALSE, 0 );
      gtk_box_pack_start( GTK_BOX( main_vbox ), hbox, TRUE, TRUE, 0 );

      pcClass->cancel = gtk_button_new_with_label( "Cancel" );
      gtk_box_pack_start( GTK_BOX( hbox ), pcClass->cancel, TRUE, TRUE, 0 );
      g_signal_connect( G_OBJECT( pcClass->cancel ), "clicked", ( GCallback )cancel, pcClass );

      gtk_widget_show_all( pcClass->dialog );
      g_thread_create( &thread, ( void * )pcClass, FALSE, NULL );
      gtk_dialog_run( GTK_DIALOG( pcClass->dialog ));
   }
   if ( pcClass != NULL ) delete pcClass;     
} // ***** Function gtkList ***** //

_________________
c/c++ for ever


Top
 Profile  
 
 Post subject: Re: g_thread_create - problem
PostPosted: Tue Apr 10, 2012 5:39 pm 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 799
Location: UK
Hi,

You can not use gdk_threads_enter()/gdk_threads_leave() under MS Windows. This is due to the differences between X11 and Win32.

Quote:
GTK+ is "thread aware" but not thread safe — it provides a global lock controlled by gdk_threads_enter()/gdk_threads_leave() which protects all use of GTK+. That is, only one thread can use GTK+ at any given time.

Unfortunately the above holds with the X11 backend only. With the Win32 backend, GDK calls should not be attempted from multiple threads at all.


See the manual at http://developer.gnome.org/gdk/stable/gdk-Threads.html

_________________
E.


Top
 Profile  
 
 Post subject: Re: g_thread_create - problem
PostPosted: Tue Apr 10, 2012 6:03 pm 
Offline
Familiar Face

Joined: Fri Mar 25, 2011 7:55 am
Posts: 35
Location: romania
errol wrote:
Hi,

You can not use gdk_threads_enter()/gdk_threads_leave() under MS Windows. This is due to the differences between X11 and Win32.

Quote:
GTK+ is "thread aware" but not thread safe — it provides a global lock controlled by gdk_threads_enter()/gdk_threads_leave() which protects all use of GTK+. That is, only one thread can use GTK+ at any given time.

Unfortunately the above holds with the X11 backend only. With the Win32 backend, GDK calls should not be attempted from multiple threads at all.


See the manual at http://developer.gnome.org/gdk/stable/gdk-Threads.html


thanks for your answer.
adding code in main function, and the above code is working in OS Win XP SP3 on my PC
i'm using gtk 2.24.8
in VirtualBox with Win XP code is working but the refresh of main window is very slow.

Code:
int main( int argc, char *argv[] ) {
   g_thread_init( NULL );
   gdk_threads_init();
.
.
   gdk_threads_enter();
   gtk_init( &argc, &argv );
.
.
.
    gtk_main ();
    gdk_threads_leave();   
}

_________________
c/c++ for ever


Top
 Profile  
 
 Post subject: Re: g_thread_create - problem
PostPosted: Tue Apr 10, 2012 6:30 pm 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 799
Location: UK
The fact that you are getting it to partially work is only due to luck.

You will need to re-write you code so that ALL GTK/GDK calls are made in the main thread, as under MS Windows GTK is not thread safe. You should not use gdk_threads_enter()/gdk_threads_leave() under MS Windows as calls to GTK/GDK MUST NOT be called from multiple threads.

You can use GLib from multiple threads as that is thread safe, so you can use it for message passing between multiple threads.

_________________
E.


Top
 Profile  
 
 Post subject: Re: g_thread_create - problem
PostPosted: Thu Apr 12, 2012 5:30 am 
Offline
Familiar Face

Joined: Fri Mar 25, 2011 7:55 am
Posts: 35
Location: romania
errol wrote:
The fact that you are getting it to partially work is only due to luck.

You will need to re-write you code so that ALL GTK/GDK calls are made in the main thread, as under MS Windows GTK is not thread safe. You should not use gdk_threads_enter()/gdk_threads_leave() under MS Windows as calls to GTK/GDK MUST NOT be called from multiple threads.

You can use GLib from multiple threads as that is thread safe, so you can use it for message passing between multiple threads.


Here is the new code, working 100% on linux, virtualbox xp, windows xp.
inserted code:

"static gboolean time_handler_catch_final( gpointer data )" catch bWorking == FALSE and destroy dialog.
"g_thread_create( &thread, ( void * )pcClass, TRUE, NULL );" joinable
"g_thread_join( Thread );" wait thread finish.
gdk_threads_enter()/gdk_threads_leave() is working 100% on xp

Code:
typedef class cList cLIST, *pcLIST;
class cList {
protected:
public:
   gboolean   bStop;
   gboolean   bWorking;
   GtkWidget *dialog;
   GtkWidget *cancel;
   GtkWidget *pbar;

   cList( pBOOL pbInitStatus );
   ~cList( void );
};

cLIST::cList( pBOOL pbInitStatus ) {
   bStop    = FALSE;
   bWorking = TRUE;
}

cLIST::~cList( void ) {
}

static void *thread( gpointer ptr ) {
   pcLIST pcClass = ( pcLIST )ptr;
   CHAR   szPercent[ 30 ] = "";
   ULONG  ulRows;
   CHAR   szBuffer[ __BUFSIZ + 1 ];
   DOUBLE dbPercent;
   int    i = 0;
   int    k = 200;

   do {
      dbPercent = (( DOUBLE )( i + 1 ) * 100.0 ) / ( DOUBLE )k;
      sprintf( szPercent, "%.2lf%%", dbPercent );
      gdk_threads_enter();
      gtk_progress_bar_set_text( GTK_PROGRESS_BAR( pcClass->pbar ), szPercent );
      gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR( pcClass->pbar ), ( dbPercent / 100.0 ) );
      gdk_flush();
      gdk_threads_leave();
      g_usleep( 1000 );
   } while (( !pcClass->bStop ) && ( ++i < k ));   
   pcClass->bWorking = FALSE;
   g_thread_exit( NULL );
   return( NULL );
}

static void cancel( GtkWidget *widget,
                    gpointer   data ) {
   pcLIST pcClass = ( pcLIST )data;

   pcClass->bStop = TRUE;
   //gtk_widget_destroy( pcClass->dialog );
}

static gboolean time_handler_catch_final( gpointer data ) {
   
   pcLIST pcClass = ( pcLIST )data;

   if ( pcClass->bWorking == FALSE ) {
      gtk_widget_destroy( pcClass->dialog );
      return( FALSE );
   }
   return TRUE;
}
void gtkList( GtkWidget *widget,
              gpointer   data ) {
   BOOL     bInitStatus = TRUE;
   pcLIST   pcClass     = new cLIST( &bInitStatus );
   GThread *Thread; 
   
   if ( pcClass != NULL ) {
      GtkWidget *main_vbox;
      GtkWidget *main_hbox;
      GtkWidget *hbox;
      GtkWidget *hseparator;

      pcClass->dialog = gtk_dialog_new();
      gtk_window_set_modal( GTK_WINDOW( pcClass->dialog ), GTK_DIALOG_MODAL );
      gtk_container_set_border_width( GTK_CONTAINER( pcClass->dialog ), 0 );
      gtk_window_set_resizable( GTK_WINDOW( pcClass->dialog ), FALSE );
      gtk_window_set_position( GTK_WINDOW( pcClass->dialog ), GTK_WIN_POS_CENTER );
      gtk_widget_set_size_request( GTK_WIDGET( pcClass->dialog ), 300, 80 );
     
      main_vbox = gtk_vbox_new( FALSE, 0 );
      gtk_container_set_border_width( GTK_CONTAINER( main_vbox ), 0 );
      gtk_container_add( GTK_CONTAINER( GTK_DIALOG( pcClass->dialog )->vbox ), main_vbox );

      hseparator = gtk_hseparator_new();
      gtk_box_pack_start( GTK_BOX( main_vbox ), hseparator, TRUE, TRUE, 0 );

      pcClass->pbar = gtk_progress_bar_new();
      gtk_box_pack_start( GTK_BOX( main_vbox ), pcClass->pbar, FALSE, FALSE, 0 );
      gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR( pcClass->pbar ), 0.0 );
      gtk_progress_bar_set_orientation( GTK_PROGRESS_BAR( pcClass->pbar ), GTK_PROGRESS_LEFT_TO_RIGHT );

      hseparator = gtk_hseparator_new();
      gtk_box_pack_start( GTK_BOX( main_vbox ), hseparator, TRUE, TRUE, 0 );

      hbox = gtk_hbox_new( FALSE, 0 );
      gtk_box_pack_start( GTK_BOX( main_vbox ), hbox, TRUE, TRUE, 0 );

      pcClass->cancel = gtk_button_new_with_label( "Cancel" );
      gtk_box_pack_start( GTK_BOX( hbox ), pcClass->cancel, TRUE, TRUE, 0 );
      g_signal_connect( G_OBJECT( pcClass->cancel ), "clicked", ( GCallback )cancel, pcClass );

      gtk_widget_show_all( pcClass->dialog );
      Thread = g_thread_create( &thread, ( void * )pcClass, TRUE, NULL );
      g_timeout_add( 100, ( GSourceFunc )time_handler_catch_final, ( gpointer )pcClass );
      gtk_dialog_run( GTK_DIALOG( pcClass->dialog ));
      g_thread_join( Thread );
   }
   if ( pcClass != NULL ) delete pcClass;     
} // ***** Function gtkList ***** //


_________________
c/c++ for ever


Top
 Profile  
 
 Post subject: Re: g_thread_create - problem
PostPosted: Thu Apr 12, 2012 6:12 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 799
Location: UK
Although this example seams to work, there are many errors which can make it fail.

1 - You have ignored the fact that GTK+ is not thread safe under MS Windows. This means you can only call GTK/GDK from one thread only. I had even given you the statement from the developers of GTK+ that it can not be called from multiple threads safely under MS Windows. If the way GTK+ works internally changes slightly then your code could fail.

2 - You access variables from multiple threads in an unsafe way. I would suggest looking up mutex or atomic access methods to protect access to any variables needed between threads or use an Inter Process Communication method.

3 - gdk_threads_enter()/gdk_threads_leave() may soon be deprecated in the coming weeks (after the release of GTK+ 3.4). So it may be a good idea not to use this method at all so that you do not have to redo all your work.

I would suggest that all calls to GTK/GDK are done in the main thread and only have worker threads to do long computation when needed and for them to communicate back to the main thread to update the user interface.

_________________
E.


Top
 Profile  
 
 Post subject: Re: g_thread_create - problem
PostPosted: Thu Apr 12, 2012 7:18 am 
Offline
Familiar Face

Joined: Fri Mar 25, 2011 7:55 am
Posts: 35
Location: romania
errol wrote:
Although this example seams to work, there are many errors which can make it fail.

1 - You have ignored the fact that GTK+ is not thread safe under MS Windows. This means you can only call GTK/GDK from one thread only. I had even given you the statement from the developers of GTK+ that it can not be called from multiple threads safely under MS Windows. If the way GTK+ works internally changes slightly then your code could fail.

2 - You access variables from multiple threads in an unsafe way. I would suggest looking up mutex or atomic access methods to protect access to any variables needed between threads or use an Inter Process Communication method.

3 - gdk_threads_enter()/gdk_threads_leave() may soon be deprecated in the coming weeks (after the release of GTK+ 3.4). So it may be a good idea not to use this method at all so that you do not have to redo all your work.

I would suggest that all calls to GTK/GDK are done in the main thread and only have worker threads to do long computation when needed and for them to communicate back to the main thread to update the user interface.


Thanks for your answer.

_________________
c/c++ for ever


Top
 Profile  
 
 Post subject: Re: g_thread_create - problem
PostPosted: Mon Apr 16, 2012 5:57 pm 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 799
Location: UK
g_timeout_add() should only be used if you do not need the information displayed immediately and is not a form of Inter Process Communication (IPC). g_idle_add() is much better as you can pass information between the processes. Other forms are available including pipes which can also be monitored using the GTK+ main loop.

_________________
E.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group