/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
- * GAsyncQueue: thread pool implementation.
+ * GThreadPool: thread pool implementation.
* Copyright (C) 2000 Sebastian Wilhelmi; University of Karlsruhe
*
* This library is free software; you can redistribute it and/or
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
#include "gthreadpool.h"
#include "gasyncqueue.h"
+#include "gasyncqueueprivate.h"
#include "gmain.h"
#include "gtestutils.h"
#include "gtimer.h"
struct _GRealThreadPool
{
GThreadPool pool;
- GAsyncQueue* queue;
- GCond *cond;
+ GAsyncQueue *queue;
+ GCond cond;
gint max_threads;
gint num_threads;
gboolean running;
/* Here all unused threads are waiting */
static GAsyncQueue *unused_thread_queue = NULL;
static gint unused_threads = 0;
-static gint max_unused_threads = 0;
+static gint max_unused_threads = 2;
static gint kill_unused_threads = 0;
-static guint max_idle_time = 0;
+static guint max_idle_time = 15 * 1000;
static void g_thread_pool_queue_push_unlocked (GRealThreadPool *pool,
gpointer data);
else if (local_max_idle_time > 0)
{
/* If a maximal idle time is given, wait for the given time. */
- GTimeVal end_time;
-
- g_get_current_time (&end_time);
- g_time_val_add (&end_time, local_max_idle_time * 1000);
-
DEBUG_MSG (("thread %p waiting in global pool for %f seconds.",
g_thread_self (), local_max_idle_time / 1000.0));
- pool = g_async_queue_timed_pop (unused_thread_queue, &end_time);
+ pool = g_async_queue_timeout_pop (unused_thread_queue,
+ local_max_idle_time * 1000);
}
else
{
/* If no maximal idle time is given, wait indefinitely. */
- DEBUG_MSG (("thread %p waiting in global pool.",
- g_thread_self ()));
+ DEBUG_MSG (("thread %p waiting in global pool.", g_thread_self ()));
pool = g_async_queue_pop (unused_thread_queue);
}
/* A thread will wait for new tasks for at most 1/2
* second before going to the global pool.
*/
- GTimeVal end_time;
-
- g_get_current_time (&end_time);
- g_time_val_add (&end_time, G_USEC_PER_SEC / 2); /* 1/2 second */
-
DEBUG_MSG (("thread %p in pool %p waits for up to a 1/2 second for task "
"(%d running, %d unprocessed).",
g_thread_self (), pool, pool->num_threads,
g_async_queue_length_unlocked (pool->queue)));
- task = g_async_queue_timed_pop_unlocked (pool->queue, &end_time);
+ task = g_async_queue_timeout_pop_unlocked (pool->queue,
+ G_USEC_PER_SEC / 2);
}
}
else
* immediately, inform the waiting thread of a change
* of the thread pool state.
*/
- g_cond_broadcast (pool->cond);
+ g_cond_broadcast (&pool->cond);
}
}
if (!success)
{
- GError *local_error = NULL;
+ GThread *thread;
/* No thread was found, we have to start a new one */
- if (!g_thread_create (g_thread_pool_thread_proxy, pool, FALSE, &local_error))
- {
- g_propagate_error (error, local_error);
- return FALSE;
- }
+ thread = g_thread_try_new ("pool", g_thread_pool_thread_proxy, pool, error);
+
+ if (thread == NULL)
+ return FALSE;
+
+ g_thread_unref (thread);
}
/* See comment in g_thread_pool_thread_proxy as to why this is done
* until it is destroyed by g_thread_pool_free(). If @exclusive is
* %FALSE, threads are created when needed and shared between all
* non-exclusive thread pools. This implies that @max_threads may
- * not be -1 for exclusive thread pools.
+ * not be -1 for exclusive thread pools. Besides, exclusive thread
+ * pools are not affected by g_thread_pool_set_max_idle_time()
+ * since their threads are never considered idle and returned to the
+ * global pool.
*
* @error can be %NULL to ignore errors, or non-%NULL to report
* errors. An error can only occur when @exclusive is set to %TRUE
* and not all @max_threads threads could be created.
+ * See #GThreadError for possible errors that may occur.
+ * Note, even in case of error a valid #GThreadPool is returned.
*
- * Return value: the new #GThreadPool
+ * Returns: the new #GThreadPool
*/
GThreadPool *
g_thread_pool_new (GFunc func,
g_return_val_if_fail (func, NULL);
g_return_val_if_fail (!exclusive || max_threads != -1, NULL);
g_return_val_if_fail (max_threads >= -1, NULL);
- g_return_val_if_fail (g_thread_supported (), NULL);
retval = g_new (GRealThreadPool, 1);
retval->pool.user_data = user_data;
retval->pool.exclusive = exclusive;
retval->queue = g_async_queue_new ();
- retval->cond = NULL;
+ g_cond_init (&retval->cond);
retval->max_threads = max_threads;
retval->num_threads = 0;
retval->running = TRUE;
+ retval->immediate = FALSE;
+ retval->waiting = FALSE;
retval->sort_func = NULL;
retval->sort_user_data = NULL;
* @data: a new task for @pool
* @error: return location for error, or %NULL
*
- * Inserts @data into the list of tasks to be executed by @pool. When
- * the number of currently running threads is lower than the maximal
- * allowed number of threads, a new thread is started (or reused) with
- * the properties given to g_thread_pool_new (). Otherwise @data stays
- * in the queue until a thread in this pool finishes its previous task
- * and processes @data.
+ * Inserts @data into the list of tasks to be executed by @pool.
+ *
+ * When the number of currently running threads is lower than the
+ * maximal allowed number of threads, a new thread is started (or
+ * reused) with the properties given to g_thread_pool_new().
+ * Otherwise, @data stays in the queue until a thread in this pool
+ * finishes its previous task and processes @data.
*
* @error can be %NULL to ignore errors, or non-%NULL to report
* errors. An error can only occur when a new thread couldn't be
*
* Before version 2.32, this function did not return a success status.
*
- * Return value: %TRUE on success, %FALSE if an error occurred
+ * Returns: %TRUE on success, %FALSE if an error occurred
*/
gboolean
g_thread_pool_push (GThreadPool *pool,
*
* Before version 2.32, this function did not return a success status.
*
- * Return value: %TRUE on success, %FALSE if an error occurred
+ * Returns: %TRUE on success, %FALSE if an error occurred
*/
gboolean
g_thread_pool_set_max_threads (GThreadPool *pool,
*
* Returns the maximal number of threads for @pool.
*
- * Return value: the maximal number of threads
+ * Returns: the maximal number of threads
*/
gint
g_thread_pool_get_max_threads (GThreadPool *pool)
*
* Returns the number of threads currently running in @pool.
*
- * Return value: the number of threads currently running
+ * Returns: the number of threads currently running
*/
guint
g_thread_pool_get_num_threads (GThreadPool *pool)
*
* Returns the number of tasks still unprocessed in @pool.
*
- * Return value: the number of unprocessed tasks
+ * Returns: the number of unprocessed tasks
*/
guint
g_thread_pool_unprocessed (GThreadPool *pool)
*
* If @immediate is %TRUE, no new task is processed for @pool.
* Otherwise @pool is not freed before the last task is processed.
- * Note however, that no thread of this pool is interrupted, while
+ * Note however, that no thread of this pool is interrupted while
* processing a task. Instead at least all still running threads
* can finish their tasks before the @pool is freed.
*
* If @wait_ is %TRUE, the functions does not return before all
* tasks to be processed (dependent on @immediate, whether all
- * or only the currently running) are ready. Otherwise the function
- * returns immediately.
+ * or only the currently running) are ready.
+ * Otherwise the function returns immediately.
*
* After calling this function @pool must not be used anymore.
*/
if (wait_)
{
- real->cond = g_cond_new ();
-
while (g_async_queue_length_unlocked (real->queue) != -real->num_threads &&
!(immediate && real->num_threads == 0))
- g_cond_wait (real->cond, _g_async_queue_get_mutex (real->queue));
+ g_cond_wait (&real->cond, _g_async_queue_get_mutex (real->queue));
}
if (immediate || g_async_queue_length_unlocked (real->queue) == -real->num_threads)
g_return_if_fail (pool->num_threads == 0);
g_async_queue_unref (pool->queue);
-
- if (pool->cond)
- g_cond_free (pool->cond);
+ g_cond_clear (&pool->cond);
g_free (pool);
}
pool->immediate = TRUE;
+ /*
+ * So here we're sending bogus data to the pool threads, which
+ * should cause them each to wake up, and check the above
+ * pool->immediate condition. However we don't want that
+ * data to be sorted (since it'll crash the sorter).
+ */
for (i = 0; i < pool->num_threads; i++)
- g_thread_pool_queue_push_unlocked (pool, GUINT_TO_POINTER (1));
+ g_async_queue_push_unlocked (pool->queue, GUINT_TO_POINTER (1));
}
/**
* Sets the maximal number of unused threads to @max_threads.
* If @max_threads is -1, no limit is imposed on the number
* of unused threads.
+ *
+ * The default value is 2.
*/
void
g_thread_pool_set_max_unused_threads (gint max_threads)
*
* Returns the maximal allowed number of unused threads.
*
- * Return value: the maximal number of unused threads
+ * Returns: the maximal number of unused threads
*/
gint
g_thread_pool_get_max_unused_threads (void)
*
* Returns the number of currently unused threads.
*
- * Return value: the number of currently unused threads
+ * Returns: the number of currently unused threads
*/
guint
g_thread_pool_get_num_unused_threads (void)
*
* By setting @interval to 0, idle threads will not be stopped.
*
- * This function makes use of g_async_queue_timed_pop () using
- * @interval.
+ * The default value is 15000 (15 seconds).
*
* Since: 2.10
*/
* If this function returns 0, threads waiting in the thread
* pool for new work are not stopped.
*
- * Return value: the maximum @interval (milliseconds) to wait
+ * Returns: the maximum @interval (milliseconds) to wait
* for new tasks in the thread pool before stopping the
* thread
*