Re: New objects for GLib
- From: Owen Taylor <otaylor redhat com>
- To: gtk-devel-list redhat com
- Subject: Re: New objects for GLib
- Date: 13 Apr 2000 15:43:55 -0400
Sebastian Wilhelmi <wilhelmi@ira.uka.de> writes:
> Hi everyone,
>
> In the course of developing the multithreaded ORBit I wrote two GLib objects,
> that might be of general interest. The first one should in fact go into GLib,
> as it offeres asyncronous communication between threads, which makes life much
> more easy (and prevents everyone from reinventing the wheel). It is just a
> small wrapper aroung GQueue, so it shouldn't be a size problem. The stripped
> .o file is about 4K.
These look reasonable and useful. (Though I haven't really done enough threaded
programming to say.)
A few comments:
> Here are the details for GAsyncQueue: (opaque datatype)
> =============================================================================
> /* Get and free GAsyncQueue */
> GAsyncQueue* g_async_queue_new (void);
> void g_async_queue_free (GAsyncQueue *queue);
>
> /* Lock and unlock an GAsyncQueue, all functions lock the queue for
> * themselves, but in certain cirumstances you want to hold the lock longer,
> * thus you lock the queue, call the *_unlocked functions and unlock it again
> */
> void g_async_queue_lock (GAsyncQueue *queue);
> void g_async_queue_unlock (GAsyncQueue *queue);
Hmmm, is this useful enough to make it worth doubling the API? What are
the common idioms where you would want to hold the lock over multiple
operations?
> /* Pop data from the async queue, when no data is there, the thread is blocked
> * until data arrives */
> gpointer g_async_queue_pop (GAsyncQueue *queue);
> gpointer g_async_queue_pop_unlocked (GAsyncQueue *queue);
>
> [...]
>
> /* Wait for data until at maximum until end_time is reached, NULL is returned
> * in case of empty queue*/
> gpointer g_async_queue_timed_pop (GAsyncQueue *queue,
> GTimeVal *end_time);
> gpointer g_async_queue_timed_pop_unlocked (GAsyncQueue *queue,
> GTimeVal *end_time);
Should we simply have the end_time as an extra parameter to pop() and allow
it to be NULL? This would be incompatible with g_cond_timed_wait), though
so perhaps it is better this way.
[...]
> The second datatype is a threadpool with automatic thread managment of GLib.
> That means unused threads of one thread pool are assigned to other thread
> pools, when needed there. To have such a thing inside a base lib is good,
> because that way different libraries/applications (e.g. ORBit and GNOME and
> the application) can use thread pools and still share the resources (the
> threads).
>
> The details are
> =============================================================================
> /* The real GThreadPool is bigger, so you can only get a thread pool with the
> * constructor function */
>
> struct _GThreadPool
> {
> GFunc thread_func;
> gulong stack_size;
> gboolean bound;
> GThreadPriority priority;
> gboolean exclusive;
> gpointer user_data;
> };
Is there any reason why this can't just be opaque?
> /* Get a thread pool with the function thread_func, at most max_threads may
> * run at a time (max_threads == -1 means no limit), stack_size, bound,
> * priority like in g_thread_create, exclusive == TRUE means, that the threads
> * shouldn't be shared and that they will be prestarted (otherwise they are
> * started, as needed) user_data is the 2nd argument to the thread_func */
>
> GThreadPool* g_thread_pool_new (GFunc thread_func,
> gint max_threads,
> gulong stack_size,
> gboolean bound,
> GThreadPriority priority,
> gboolean exclusive,
> gpointer user_data);
I don't quite understand exclusive. If exclusive == FALSE, do all GThreadPool
objects share a larger actual pool of threads?
In general, these do look like good additions to me.
Along similar lines, but a bit more substantial in terms of the work necessary,
I want to make it possible to have per-thread main loop contexts in GLib 1.4.
The API I'm thinking of for this is that:
GMainContext *g_main_context_get_current ();
Gets the main loop for the current thread.
GMainContext *g_main_context_get_default ();
Gets the default main loop; which would be the main loop in the first thread
that called g_main_get_default() either explicitely or implicitely. All the
source. All the source functions are shadowed like:
g_main_add_timeout (GMainContext *main_context,
guint interval,
GSourceFunc function,
gpointer data);
g_timout_add() becomes implemented as:
g_main_add_timeout (g_main_context_get_default(), ...);
Because iterating the main loop context for a different thread is not permissable,
g_main_iterate () always iterate the main loop context for the current thread,
not the default thread. However, there is:
GMainLoop *g_main_context_create_main_loop (GMainContext *main_context);
And g_main_loop_new() becomes:
g_main_context_create_main_loop (g_main_get_default ());
The way this works is that if g_main_run(); is done in thread other
than the thread corresponding main loop context for which the
GMainLoop was created, then what g_main_run() does is create a
condition variable and wait until g_main_quit() is called instead of
iterating the main loop until g_main_quit() is called.
The last allows non-main threads to put up modal dialogs without
doing anything special - they just do:
GMainLoop *loop = g_main_loop_new ();
gtk_signal_connect (window, "destroy", GTK_SIGNAL_FUNC (g_main_quit), looop);
g_main_run (loop);
Note that there is some bad naming problems here since in my initial
implementation I took over both the GMain and GMainLoop namespaces,
leading to the
g_main_context_create_main_loop ()
monstrosity.
Regards,
Owen
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]