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

A thread object -- GtkThread



    I've been working on a wraper to threads as a GTK object, using the
wonderful gob. The file is in attachment. If anyone would like to use it,
go ahead.

    How it works: 
	- a GtkThread object is created -- it manages a single thread;
	- signal handlers for termination and cancelation of the thread
can be connected;
	- gtk_thread_launch (function, arg) creates the thread and
returns;
	- a timeout function is registered, which monitors the thread for
completion;
	- when the thread terminates, it is joined, the object emits a
signal and the function removes itself;

    The question is: is there a better way to do this? Specifically, I
don't know of any function from the pthread library to check if a thread
has terminated -- I'm using a flag and the timeout function. I don't like
this very much, but it's the best I could do. 

    Any ideas, sugestions, bugs, etc.?

    PS: If anyone is interested in a wraper to GSList, I have one.

-- 
Gustavo J.A.M. Carneiro [reinolinux.fe.up.pt/~ee96090]
                                       
/* -*- Mode: C; c-file-style: "bsd"; coding: latin-1-unix -*- */
%h{

#include <pthread.h>

typedef void * (*GtkThreadRoutine)(void *);
extern int gtk_thread_disable_threads;
%}

%{
typedef void * (*ThreadFunction)(void *);
typedef void (*ThreadCleanUpFunc)(void *);

int gtk_thread_disable_threads=0;

%}

class Gtk:Thread from Gtk:Object 
{
    protected pthread_t thread;
    protected gboolean running;
    protected gboolean busy;
    protected guint timeout_handler_id;
    public void *return_value;
    public gint check_interval;
    protected GtkThreadRoutine routine;
    protected void * arg;
    
    init(self) {
	self->running = FALSE;
	self->busy = FALSE;
	self->check_interval = 10;
    }

    public GtkObject * new(void) {
	return GTK_OBJECT(GET_NEW);
    }

    signal private NONE (POINTER) void finished(self, void *ret_val);

    signal private NONE (NONE) void canceled(self);

    public gboolean launch(self, GtkThreadRoutine routine, void * ARG) {
	gint err;

	if(self->busy)
	    return FALSE;
	self->busy = TRUE;
	self->routine = routine;
	self->arg = ARG;
	self->running = TRUE;
	if(gtk_thread_disable_threads) 
	{
	    void *ret;
	    ret = routine(ARG);
	    self->running = FALSE;
	    finished(self, ret);
	    self->busy = FALSE;
	    return TRUE;
	}
	err = pthread_create(&self->thread, NULL, (ThreadFunction)marshaller, self);
	if(err) g_warning("pthread_create failed!");
	self->timeout_handler_id = gtk_timeout_add(self->check_interval, 
						   (GtkFunction)check_thread_termination, 
						   self);
	return TRUE;
    }

    /* This function runs periodically in gtk's main loop with a
       timeout. It monitors the completion of a thread. When
       completed, it pthread_join's the thread and emits a gtk
       signal. The function then returns FALSE to stop itself from
       being called anymore. */
    private gint check_thread_termination (void *foo) {
	GtkThread *self;

	gdk_threads_enter();
	self = GTK_THREAD(foo);
	if (self->running) {
	    gdk_threads_leave();
	    return TRUE;
	}
	if(pthread_join(self->thread, &self->return_value))
	    g_warning("pthread_join failed!");
	self->busy = FALSE;
	finished(self, self->return_value);
	gdk_threads_leave();
	return FALSE;
    }

    /* This function calls the user routine, but first it installs a
       cleanup handler which changes the flag self->running to
       FALSE. The function 'check_thread_termination', that runs in the
       main thread as a timeout function, monitors that flag. */
    private void * marshaller (void *foo) {
	GtkThread *self;
	void *ret_val;

	self = (GtkThread*)foo;
	printf(__FUNCTION__"\n");
	if(!self) return NULL;
	pthread_cleanup_push((ThreadCleanUpFunc)thread_cleanup, self);
	
	ret_val = self->routine(self->arg);
    
	pthread_cleanup_pop(TRUE);
	return ret_val;
    }

    private void thread_cleanup (void *arg) {
	GtkThread *self;

	g_return_if_fail(arg);
	self = (GtkThread *)arg;
	self->running = FALSE;
    }

    /* Before destroying the object, cancel it. */
    override (Gtk:Object) void destroy(Gtk:Object *object) {
	GtkThread *self;
	
	self = GTK_THREAD(object);
	cancel (self);
	PARENT_HANDLER(object);
    }

    /* Send a cancelation request to the thread, then join it, in case
       it is running.  */
    public void cancel (self) {
	if(self->busy) {
	    pthread_cancel(self->thread);
	    pthread_join(self->thread, NULL);
	    gtk_timeout_remove (self->timeout_handler_id);
	    self->busy = FALSE;
	    canceled(self);
	}
    }



}





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