Re: New objects for GLib




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]