c - GTK3 and multithreading, replacing deprecated functions -


i replace deprecated functions gdk_threads_enter()/leave() in application uses threads. application now, works perfect (although not sure if right way it).

my main loop, runs gtk_main , signal handlers. when receive start button, start thread, runs in background along main. how can update gui thread. know per documentation of gtk3 , gdk3, avoid using

gdk_threads_add_idle()  

or

gdk_threads_add_timeout()  

but how do if want updating done when click start? there example. not asking how use gdk_threads_add_idle(), asking how run worker function in main without thread after clicking start.

button clicked --> start worker function "in thread previously" --> update large amount of gui elements in gui window.

you have 3 ways it:

  1. make computation in button callback , use gtk_event_pending()/gtk_main_iteration()

  2. use g_idle_add() or others, , gtk_event_pending()/gtk_main_iteration()

  3. use thread, mutex, , g_idle_add() or others. normally, mutex isn't needed may solve bugs or heisenbugs.

the third solution seems best, because first two methods, experienced problems when exiting application while computation running. application didn't exit , printing lot of "gtk critical" warnings. (i tried on windows , mingw32).


1. button callback:

if want run worker thread in main gtk loop, can directly make computation in button callback, updating gui , treating events gtk_event_pending() , gtk_main_iteration(), in following sample code:

void on_button_clicked(gtkbutton * button, gpointer data) {    // computation...    // modify gui:   gtk_label_set_text(label,"text");    // run main iteration update gui,   // need call these functions if gui wasn't modified,   // in order responsive , treat events it:   while(gtk_events_pending()) gtk_main_iteration();    // other computation...    // huge computation in loop:   while(1) {     // computation...      // update gui , treat events it:     while(gtk_events_pending()) gtk_main_iteration();   } } 

2. g_idle_add():

you can use, instead of g_thread_new(), gdk_thread_add_idle()(in case libraries not under control may use gdk_threads_enter()/leave()) or g_idle_add() or g_main_context_invoke():

gboolean compute_func(gpointer data) {    // computation...    // modify gui:   gtk_label_set_text(label,"text");   // run main loop update gui , responsive:   while(gtk_events_pending()) gtk_main_iteration();    // other computation...    // huge computation in loop:   while(1) {     // computation...      // update gui , treat events it:     while(gtk_events_pending()) gtk_main_iteration();   }    return false; }  void on_button_clicked(gtkbutton * button, gpointer data) {      g_idle_add(compute_func,data); } 

3. thread , mutex:

in some cases using thread make computation faster, when using worker thread not in main gtk loop, , when updating gui in function added main loop gdk_threads_add_idle() or g_idle_add() worker thread, may have lock access gui using mutex, because there may conflict between functions accessing gui. mutex have initialized g_mutex_init(&mutex_interface); before beeing used application. example:

gmutex mutex_interface;  gboolean update_gui(gpointer data) {   g_mutex_lock(&mutex_interface);   // update gui here:   gtk_button_set_label(button,"label");   // , read gui here, before mutex unlocked:   gchar * text = gtk_entry_get_text(gtk_entry(entry));   g_mutex_unlock(&mutex_interface);    return false; }  gpointer threadcompute(gpointer data) {   int count = 0;    while(count <= 10000) {     printf("\ntest %d",count);     // update gui:     gdk_threads_add_idle(update_gui,data);     // or:     g_idle_add(update_gui,data);      count++;   }    return null; }  void on_button_clicked(gtkbutton * button, gpointer data) {      g_thread_new("thread",threadcompute,data); } 

if need functions updating gui executed in specific order, need add 2 counters , assign number each function called g_idle_add() or gdk_threads_add_ilde():

gmutex mutex_interface;  typedef struct _data data; struct _data {   gchar label[1000];   gtkwidget * w;   int num; };   int counter = 0; int counter2 = 0;  gboolean update_gui(gpointer data) {   data * d = (data *)data;    debutloop:   g_mutex_lock(&mutex_interface);   if(d->num != counter2) {     g_mutex_unlock(&mutex_interface);     goto debutloop;   }   counter2++;   // update gui here:   gtk_button_set_label(gtk_button(d->w),d->label);   // , read gui here, before mutex unlocked:   gchar * text = gtk_entry_get_text(gtk_entry(entry));   g_mutex_unlock(&mutex_interface);    free(d);    return false; }  gpointer threadcompute(gpointer data) {   int count = 0;    while(count <= 10000) {     printf("\ntest %d",count);      data * d = (data*)malloc(sizeof(data));     sprintf(d->label,"%d",count);     d->w = (gtkwidget*)data;     d->num = counter;     counter++;     // update gui:     g_idle_add(update_gui,d);      count++;   }   return null; }  void on_button_clicked(gtkbutton * button, gpointer data) {      g_thread_new("thread",threadcompute,button); } 

i have tested case of locking individual widgets instead of whole gui, , seems work.


Comments

Popular posts from this blog

python - TypeError: start must be a integer -

c# - DevExpress RepositoryItemComboBox BackColor property ignored -

django - Creating multiple model instances in DRF3 -