[glib: 2/4] glib/test/thread-pool-slow: Ensure all unused threads are really stopped
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib: 2/4] glib/test/thread-pool-slow: Ensure all unused threads are really stopped
- Date: Tue, 12 Jul 2022 11:44:06 +0000 (UTC)
commit fabdc2d4fa4d9f3cb141f515ed637bba35f27e3f
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date: Mon Jul 11 18:17:41 2022 +0200
glib/test/thread-pool-slow: Ensure all unused threads are really stopped
In this tests we wanted to ensure that all the unused threads were
stopped, however while we were calling g_thread_pool_stop_unused_threads
some threads could still be in the process of being recycled even tough
the pool's num_thread values are 0.
In fact, stopping unused threads implies also resetting back the max
unused threads to the previous value, and in this test it caused it to
go from -1 -> 0 and back to -1, after killing the unused threads we
knew about; thus any about-to-be-unused thread that is not killed during
this call will be just left around as a waiting unused thread afterwards.
However, if this function was getting called when a thread was in
between of calling the user function and the moment it was being
recycled (and so when the pool num_threads was updated), but this thread
was not counted in unused_threads, we ended up in having a race because
all the threads were consumed from our POV, but some were actually not
yet unused, and so were kept waiting forever for some new job.
To avoid this in the test, we can ensure that we stop the unused
threads until we the number of them is really 0.
Sadly we need to repeat this as we don't have a clear point in which we
are sure about the fact that our threads are done, while it would be
wrong to stop a thread that is technically not yet marked as unused.
We could also do this in g_thread_pool_stop_unused_threads() itself, but
it would make such function to wait for threads to complete, and this is
probably not what was expected in the initial API.
Fixes: #2685
glib/tests/thread-pool-slow.c | 34 ++++++++++++++++------------------
1 file changed, 16 insertions(+), 18 deletions(-)
---
diff --git a/glib/tests/thread-pool-slow.c b/glib/tests/thread-pool-slow.c
index 3706754c4b..a7d3039ec3 100644
--- a/glib/tests/thread-pool-slow.c
+++ b/glib/tests/thread-pool-slow.c
@@ -61,47 +61,45 @@ test_thread_functions (void)
g_assert_cmpint (g_thread_pool_get_max_idle_time (), ==, 0);
}
-static void
-thread_wait_func (gpointer data,
- gpointer user_data)
-{
- guint timeout_ms = GPOINTER_TO_UINT (data);
- guint *n_threads_executed = user_data;
-
- g_usleep (timeout_ms);
-
- g_atomic_int_inc (n_threads_executed);
-}
-
static void
test_thread_stop_unused (void)
{
GThreadPool *pool;
guint i;
guint limit = 100;
- guint n_threads_executed = 0;
/* Spawn a few threads. */
g_thread_pool_set_max_unused_threads (-1);
- pool = g_thread_pool_new (thread_wait_func, &n_threads_executed, -1, FALSE, NULL);
+ pool = g_thread_pool_new ((GFunc) g_usleep, NULL, -1, FALSE, NULL);
for (i = 0; i < limit; i++)
g_thread_pool_push (pool, GUINT_TO_POINTER (1000), NULL);
/* Wait for the threads to migrate. */
- while ((guint) g_atomic_int_get (&n_threads_executed) < limit)
+ while (g_thread_pool_get_num_threads (pool) != 0)
g_usleep (100);
- g_thread_pool_stop_unused_threads ();
+ g_assert_cmpuint (g_thread_pool_get_num_threads (pool), ==, 0);
/* Wait for threads to die. */
- while (g_thread_pool_get_num_unused_threads () != 0)
+ do {
+ /* We may need to repeat this in case we tried to stop unused threads
+ * while some thread was still active, and not yet marked as non-used,
+ * despite what g_thread_pool_get_num_threads() tells us.
+ * And if this happens the thread will be kept in the unused queue
+ * indefinitely, so we need to stop it again, until we're really done.
+ */
+ g_thread_pool_stop_unused_threads ();
g_usleep (100);
+ } while (g_thread_pool_get_num_unused_threads () != 0);
- g_assert_cmpint (g_thread_pool_get_num_unused_threads (), ==, 0);
+ g_assert_cmpuint (g_thread_pool_get_num_unused_threads (), ==, 0);
g_thread_pool_set_max_unused_threads (MAX_THREADS);
+ g_assert_cmpuint (g_thread_pool_get_num_threads (pool), ==, 0);
+ g_assert_cmpuint (g_thread_pool_get_num_unused_threads (), ==, 0);
+
g_thread_pool_free (pool, FALSE, TRUE);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]