From 75db4883fc4bbe47766b6bd5f939b8154ef5e98e Mon Sep 17 00:00:00 2001 From: nitinosiris Date: Sat, 26 Jun 2021 16:08:42 +0530 Subject: [PATCH] GThreadPool: Add g_thread_pool_new_full() g_thread_pool_new_full() is similar to g_thread_pool_new() but with GDestroyNotify argument. Closes #121 --- docs/reference/glib/glib-sections.txt | 1 + glib/gthreadpool.c | 34 +++++++++++++++- glib/gthreadpool.h | 7 ++++ glib/tests/thread-pool.c | 56 +++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 1 deletion(-) diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index 863dc5a1b..406041253 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -1171,6 +1171,7 @@ g_once_init_enter_impl thread_pools GThreadPool g_thread_pool_new +g_thread_pool_new_full g_thread_pool_push g_thread_pool_set_max_threads g_thread_pool_get_max_threads diff --git a/glib/gthreadpool.c b/glib/gthreadpool.c index 305152ae7..15d5d4e52 100644 --- a/glib/gthreadpool.c +++ b/glib/gthreadpool.c @@ -558,6 +558,38 @@ g_thread_pool_new (GFunc func, gint max_threads, gboolean exclusive, GError **error) +{ + return g_thread_pool_new_full (func, user_data, NULL, max_threads, exclusive, error); +} + +/** + * g_thread_pool_new_full: + * @func: a function to execute in the threads of the new thread pool + * @user_data: user data that is handed over to @func every time it + * is called + * @item_free_func: (nullable): used to pass as a free function to + * g_async_queue_new_full() + * @max_threads: the maximal number of threads to execute concurrently + * in the new thread pool, `-1` means no limit + * @exclusive: should this thread pool be exclusive? + * @error: return location for error, or %NULL + * + * This function creates a new thread pool similar to g_thread_pool_new() + * but allowing @item_free_func to be specified to free the data passed + * to g_thread_pool_push() in the case that the #GThreadPool is stopped + * and freed before all tasks have been executed. + * + * Returns: (transfer full): the new #GThreadPool + * + * Since: 2.70 + */ +GThreadPool * +g_thread_pool_new_full (GFunc func, + gpointer user_data, + GDestroyNotify item_free_func, + gint max_threads, + gboolean exclusive, + GError **error) { GRealThreadPool *retval; G_LOCK_DEFINE_STATIC (init); @@ -571,7 +603,7 @@ g_thread_pool_new (GFunc func, retval->pool.func = func; retval->pool.user_data = user_data; retval->pool.exclusive = exclusive; - retval->queue = g_async_queue_new (); + retval->queue = g_async_queue_new_full (item_free_func); g_cond_init (&retval->cond); retval->max_threads = max_threads; retval->num_threads = 0; diff --git a/glib/gthreadpool.h b/glib/gthreadpool.h index 11c3d1d16..f2501b88b 100644 --- a/glib/gthreadpool.h +++ b/glib/gthreadpool.h @@ -51,6 +51,13 @@ GThreadPool * g_thread_pool_new (GFunc func, gint max_threads, gboolean exclusive, GError **error); +GLIB_AVAILABLE_IN_2_70 +GThreadPool * g_thread_pool_new_full (GFunc func, + gpointer user_data, + GDestroyNotify item_free_func, + gint max_threads, + gboolean exclusive, + GError **error); GLIB_AVAILABLE_IN_ALL void g_thread_pool_free (GThreadPool *pool, gboolean immediate, diff --git a/glib/tests/thread-pool.c b/glib/tests/thread-pool.c index 703da5d7a..50a72a632 100644 --- a/glib/tests/thread-pool.c +++ b/glib/tests/thread-pool.c @@ -87,6 +87,12 @@ dummy_pool_func (gpointer data, gpointer user_data) g_assert_true (data == GUINT_TO_POINTER (123)); } +static void +dummy_pool_func_full (gpointer data, gpointer user_data) +{ + g_assert_true (data == user_data); +} + static void test_create_first_pool (gconstpointer shared_first) { @@ -142,6 +148,55 @@ test_create_first_pool (gconstpointer shared_first) g_thread_pool_free (pool, TRUE, TRUE); } +static void +free_func (gpointer user_data) +{ + gboolean *free_func_called = user_data; + *free_func_called = TRUE; +} + +static void +test_thread_pool_full (gconstpointer shared_first) +{ + GThreadPool *pool; + gboolean free_func_called = FALSE; + GError *err = NULL; + gboolean success; + + g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/121"); + + g_thread_pool_set_max_unused_threads (0); + + if (GPOINTER_TO_INT (shared_first)) + pool = g_thread_pool_new_full (dummy_pool_func_full, &free_func_called, free_func, -1, FALSE, &err); + else + pool = g_thread_pool_new_full (dummy_pool_func_full, &free_func_called, free_func, 2, TRUE, &err); + g_assert_no_error (err); + g_assert_nonnull (pool); + + success = g_thread_pool_push (pool, &free_func_called, &err); + g_assert_no_error (err); + g_assert_true (success); + + g_thread_pool_free (pool, TRUE, TRUE); + g_assert_true (free_func_called); + + free_func_called = FALSE; + if (GPOINTER_TO_INT (shared_first)) + pool = g_thread_pool_new_full (dummy_pool_func_full, &free_func_called, free_func, 2, TRUE, &err); + else + pool = g_thread_pool_new_full (dummy_pool_func_full, &free_func_called, free_func, -1, FALSE, &err); + g_assert_no_error (err); + g_assert_nonnull (pool); + + success = g_thread_pool_push (pool, &free_func_called, &err); + g_assert_no_error (err); + g_assert_true (success); + + g_thread_pool_free (pool, TRUE, TRUE); + g_assert_true (free_func_called); +} + int main (int argc, char *argv[]) { @@ -150,6 +205,7 @@ main (int argc, char *argv[]) g_test_add_data_func ("/thread_pool/shared", GINT_TO_POINTER (TRUE), test_simple); g_test_add_data_func ("/thread_pool/exclusive", GINT_TO_POINTER (FALSE), test_simple); g_test_add_data_func ("/thread_pool/create_shared_after_exclusive", GINT_TO_POINTER (FALSE), test_create_first_pool); + g_test_add_data_func ("/thread_pool/create_full", GINT_TO_POINTER (FALSE), test_thread_pool_full); g_test_add_data_func ("/thread_pool/create_exclusive_after_shared", GINT_TO_POINTER (TRUE), test_create_first_pool); return g_test_run ();