2014-02-15 17:02 GMT+02:00 David Marceau <uticdmarceau2...@yahoo.ca>: > Here is an example that shows two threads which take a long time to > complete, but gracefully coordinate progress data to the gui. > http://www.simsoup.info/SimSoup/GUI_With_Worker_Threads.html That didn't helped :-((((((99
2014-02-15 19:43 GMT+02:00 Andrew Potter <agpot...@gmail.com>: > Problem 1) Passing stack variables from a worker thread is dangerous. > Problem 2) Reading and writing variables across threads is dangerous. I believe this 'example' would be very usefull for many and it has to be finished. I've modified the code around and now I have a funny construction: callobj->thread_data = thread_data; thread_data->callobj = callobj; I'm not sure if this needs fix or not, and how to fix it approximately. Also it appears to be that I have to use GOnce for a single event in thread? And I started to wonder how the thread might be paused. >You can also annotate messagebox() with the > G_GNUC_PRINTF(2, 3) macro to enable compile-time format checking for > calls to that function. Awesome!!1 // ############################################################################# // GThread with GTK+-3.10 // v2 #include <stdlib.h> #include <gtk/gtk.h> // ############################################################################# struct THREAD_DATA { struct CallbackObject *callobj; GThread *pthread; GCancellable *cancel; GRWLock lock; guint event_source; GtkWidget *progress; gdouble x; }; struct CallbackObject { GtkWidget *win; GtkWidget *label; GtkWidget *button; GtkWidget *progress; struct THREAD_DATA *thread_data; }; // ############################################################################# void messagebox (struct CallbackObject *callobj, gchar *format, ...) G_GNUC_PRINTF (2, 3); gboolean thread_exit (struct THREAD_DATA *data); gboolean thread_progress (struct THREAD_DATA *data); gboolean thread_cb (struct THREAD_DATA *data); gpointer thread_func (struct THREAD_DATA *data); void startstop_thread (GtkWidget *wid, struct CallbackObject *callobj); // ############################################################################# const gchar *label_start = "Start thread"; const gchar *label_stop = "Stop thread"; // ############################################################################# void messagebox (struct CallbackObject *callobj, gchar *format, ...) { GtkWidget *dialog = NULL; // Write a formatted string into a GString. va_list arg; va_start (arg, format); GString *msg = g_string_new (NULL); g_string_vprintf (msg, format, arg); // Create the message dialog dialog = gtk_message_dialog_new (GTK_WINDOW(callobj->win), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, msg->str); gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); gtk_dialog_run (GTK_DIALOG(dialog)); gtk_widget_destroy (dialog); g_string_free (msg, TRUE); va_end (arg); } // ############################################################################# gboolean thread_exit (struct THREAD_DATA *data) { struct CallbackObject *callobj = data->callobj; /* Wait thread to finish */ g_thread_join (data->pthread); g_thread_unref (data->pthread); data->pthread = NULL; /* Stop progress update and update once more to get "100%" */ g_source_remove (data->event_source); thread_progress (data); /* Restore GUI state */ gtk_label_set_label (GTK_LABEL(data->callobj->label), ""); gtk_button_set_label (GTK_BUTTON (data->callobj->button), label_start); if (g_cancellable_is_cancelled (data->cancel) == TRUE) { messagebox (data->callobj, "Thread cancelled!"); } else { messagebox (data->callobj, "Thread successfully completed!"); } /* Cleanup */ g_object_unref (data->cancel); data->cancel = NULL; g_rw_lock_clear (&(data->lock)); g_free (data); callobj->thread_data = NULL; return G_SOURCE_REMOVE; } gboolean thread_progress (struct THREAD_DATA *data) { g_rw_lock_reader_lock (&(data->lock)); gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (data->progress), data->x); g_rw_lock_reader_unlock (&(data->lock)); return G_SOURCE_CONTINUE; } gboolean thread_cb (struct THREAD_DATA *data) { gtk_label_set_label (GTK_LABEL(data->callobj->label), "Reached level 50% !"); return G_SOURCE_REMOVE; } gpointer thread_func (struct THREAD_DATA *data) { guint event_source_cb = 0; while (data->x < 1.0 && g_cancellable_is_cancelled (data->cancel) == FALSE) { g_rw_lock_writer_lock (&(data->lock)); data->x += 1.0 / 100; g_rw_lock_writer_unlock (&(data->lock)); /* Process code */ usleep (10*1000); if (data->x >= 0.5 && event_source_cb == 0) { event_source_cb = g_idle_add ((GSourceFunc) thread_cb, data); } } g_idle_add ((GSourceFunc) thread_exit, data); return NULL; } // ############################################################################# void startstop_thread (GtkWidget *wid, struct CallbackObject *callobj) { if (callobj->thread_data == NULL) { /* Prepare the structure and start the progress bar update */ struct THREAD_DATA *thread_data = g_new0 (struct THREAD_DATA, 1); callobj->thread_data = thread_data; thread_data->callobj = callobj; thread_data->cancel = g_cancellable_new (); g_rw_lock_init (&(thread_data->lock)); thread_data->progress = callobj->progress, thread_data->x = 0.0; thread_data->event_source = g_timeout_add (20 /* ms */, (GSourceFunc) thread_progress, thread_data); /* Thread starts here */ thread_data->pthread = g_thread_new ("thread", (GThreadFunc) thread_func, thread_data); /* Change GUI state */ gtk_button_set_label (GTK_BUTTON (callobj->button), label_stop); } else { g_cancellable_cancel (callobj->thread_data->cancel); } } // ############################################################################# int main (int argc, char *argv[]) { GtkWidget *button = NULL; GtkWidget *vbox = NULL; struct CallbackObject *callobj = NULL; /* Initialize GTK+ */ g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING, (GLogFunc) gtk_false, NULL); gtk_init (&argc, &argv); g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING, g_log_default_handler, NULL); callobj = g_malloc0 (sizeof(struct CallbackObject)); /* Create the main window */ callobj->win = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_container_set_border_width (GTK_CONTAINER (callobj->win), 8); gtk_window_set_title (GTK_WINDOW (callobj->win), "GTK+-3.10.7-1 Threads"); gtk_window_set_position (GTK_WINDOW (callobj->win), GTK_WIN_POS_CENTER); gtk_widget_realize (callobj->win); g_signal_connect (callobj->win, "destroy", gtk_main_quit, NULL); /* Create a vertical box with buttons */ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4); gtk_container_add (GTK_CONTAINER (callobj->win), vbox); callobj->label = gtk_label_new (""); gtk_box_pack_start (GTK_BOX (vbox), callobj->label, TRUE, TRUE, 0); callobj->progress = gtk_progress_bar_new (); gtk_progress_bar_set_show_text (GTK_PROGRESS_BAR (callobj->progress), TRUE); gtk_box_pack_start (GTK_BOX (vbox), callobj->progress, TRUE, TRUE, 0); callobj->button = gtk_button_new_with_label ("Start thread"); g_signal_connect (G_OBJECT (callobj->button), "clicked", G_CALLBACK (startstop_thread), (gpointer) callobj); gtk_box_pack_start (GTK_BOX (vbox), callobj->button, TRUE, TRUE, 0); button = gtk_button_new_with_label ("Close"); g_signal_connect (button, "clicked", gtk_main_quit, NULL); gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0); /* Enter the main loop */ gtk_widget_show_all (callobj->win); gtk_main (); g_free (callobj); return 0; } // ############################################################################# _______________________________________________ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list