GTK Threads example, version 0.2



I've cleaned up my previously posted gtkthreads.c example (sorry I don't have the original messages so I can't continue the thread). There were a number of compile warnings that may or may not have been harmless. Actually in one case there was a memory leak (on the g_string_free call) that would bite a person if this code was ever put in some large program.

Some caveats about my code:
- Resource management isn't really done well. I have not made sure to clean up every resource I allocated. - No thread signal handling is performed so a thread exception will just kill the whole program - This is basic, minimal stuff. I'm not getting into IPC or using synchronization primitives or message queues, as a real multithreaded program would.

This example code is not the one true way to do threads, but merely an example of how to do threading in the context of the original poster's needs.

Michael
#include <gtk/gtk.h>
#include <glib.h>
#include <pthread.h>

gint thread_count=0;
gint dead_threads;

GSList *threads;

struct thread_info_data {
	GtkTextBuffer *buffer;
	gint id;
	pthread_t tid;
	gint terminate;
};

void *thread (void *data) {
	struct thread_info_data *info;
	GtkTextIter iter;
	GString *message;


	info=(struct thread_info_data *)data;
	message=g_string_new("");

	while(info->terminate == 0 ) {
		sleep(1);
		g_string_printf(message,"Thread %d here.\n",info->id);
		g_print("%s",message->str);
		
		gdk_threads_enter();
		gtk_text_buffer_get_end_iter(info->buffer,&iter);
		gtk_text_buffer_insert(info->buffer,&iter,message->str,-1);
		gdk_threads_leave();
	}
	g_print("Thread %d stopping.\n",info->id);
	gdk_threads_enter(); //borrowing a lock from gtk to lock our variable
	dead_threads++;
	gdk_threads_leave(); //we could and should use a counting semaphore
	g_string_free(message,TRUE);
	return NULL;
}

void stop_thread(gpointer data, gpointer user_data) {
	struct thread_info_data *thread;

	thread=data;
	thread->terminate=1;
	g_print("Asked thread %d to stop.\n",thread->id);
	
	//here we ought to make sure the thread really has died
//	pthread_join(thread->tid,NULL);
}

void on_destroy(GtkWidget *widget, gpointer data) {
	g_slist_foreach(threads,stop_thread,NULL);

	while(dead_threads < thread_count) {
		while(gtk_events_pending()) {
			gtk_main_iteration();
		}
		sleep(0);
	}
	gtk_main_quit();
}

void on_button_clicked(GtkWidget *widget, gpointer data) {
	GtkTextBuffer *buffer;
	GtkTextIter iter;
	struct thread_info_data *thread_info;
	
	buffer=GTK_TEXT_BUFFER(data);

	thread_info=g_malloc(sizeof(struct thread_info_data));
	thread_info->buffer=buffer;
	thread_info->id=thread_count++;
	thread_info->terminate=0;

	threads=g_slist_append(threads,thread_info);

	pthread_create(&(thread_info->tid),NULL,thread,thread_info);
	

	gtk_text_buffer_get_end_iter(buffer,&iter);
	gtk_text_buffer_insert(buffer,&iter,"Button clicked!\n",-1);
	g_print("Button clicked.\n");


}


int main(int argc, char *argv[]) {
	GtkWidget *window;
	GtkWidget *button;
	GtkWidget *vbox;
	GtkWidget *viewarea;
	GtkWidget *view;
	GtkTextBuffer *buffer;

	threads=NULL;


	g_thread_init (NULL);
	gdk_threads_init ();

	gtk_init(&argc, &argv);

	window=gtk_window_new(GTK_WINDOW_TOPLEVEL);

	gtk_signal_connect(GTK_OBJECT(window),"destroy",
	                   GTK_SIGNAL_FUNC(on_destroy),NULL);
	gtk_container_set_border_width(GTK_CONTAINER(window),10);

	vbox=gtk_vbox_new(FALSE,5);
	gtk_container_add(GTK_CONTAINER(window),vbox);
	gtk_widget_show(vbox);

	viewarea=gtk_scrolled_window_new(NULL,NULL);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(viewarea),
	                               GTK_POLICY_AUTOMATIC,
				       GTK_POLICY_AUTOMATIC);
	gtk_box_pack_start(GTK_BOX(vbox),viewarea,TRUE,TRUE,2);
	gtk_widget_show(viewarea);
	
	view=gtk_text_view_new();

	buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));

	gtk_text_buffer_set_text(buffer,"The threads will write here.\n",-1);
	gtk_container_add(GTK_CONTAINER(viewarea),view);
	gtk_widget_show(view);
	
	button=gtk_button_new_with_label("Click me");
	gtk_signal_connect(GTK_OBJECT(button),"clicked",
	                   GTK_SIGNAL_FUNC(on_button_clicked),buffer);
			   
	gtk_box_pack_end(GTK_BOX(vbox),button,FALSE,FALSE,3);
	
	gtk_widget_show(button);
	gtk_widget_show(window);

	gdk_threads_enter ();
	gtk_main();
	gdk_threads_leave ();

	return 0;
}



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