[glib: 1/2] GThread - Inherit parent thread priority by default for new Win32 threads



commit be537d8b51ebbb00a59b2dcdd7cf6bdf8bd4d7f9
Author: Sebastian Dröge <sebastian centricular com>
Date:   Tue Sep 17 17:27:50 2019 +0300

    GThread - Inherit parent thread priority by default for new Win32 threads
    
    This is the default behaviour on POSIX and having different behaviour
    between the two GThread implementations could lead to subtle problems.

 glib/gthread-win32.c | 56 +++++++++++++++++++++++++++++++++++++++++++++-------
 glib/gthread.c       |  8 ++++++++
 2 files changed, 57 insertions(+), 7 deletions(-)
---
diff --git a/glib/gthread-win32.c b/glib/gthread-win32.c
index 89df0daa0..9cbe2bcfb 100644
--- a/glib/gthread-win32.c
+++ b/glib/gthread-win32.c
@@ -439,9 +439,13 @@ g_system_thread_new (GThreadFunc   proxy,
   GThreadWin32 *thread;
   GRealThread *base_thread;
   guint ignore;
+  const gchar *message = NULL;
+  HANDLE current_thread;
+  int current_prio;
 
   thread = g_slice_new0 (GThreadWin32);
   thread->proxy = proxy;
+  thread->handle = (HANDLE) NULL;
   base_thread = (GRealThread*)thread;
   base_thread->ref_count = 2;
   base_thread->ours = TRUE;
@@ -450,19 +454,57 @@ g_system_thread_new (GThreadFunc   proxy,
   base_thread->thread.data = data;
   base_thread->name = g_strdup (name);
 
-  thread->handle = (HANDLE) _beginthreadex (NULL, stack_size, g_thread_win32_proxy, thread, 0, &ignore);
+  thread->handle = (HANDLE) _beginthreadex (NULL, stack_size, g_thread_win32_proxy, thread,
+                                            CREATE_SUSPENDED, &ignore);
 
   if (thread->handle == NULL)
     {
-      gchar *win_error = g_win32_error_message (GetLastError ());
-      g_set_error (error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN,
-                   "Error creating thread: %s", win_error);
-      g_free (win_error);
-      g_slice_free (GThreadWin32, thread);
-      return NULL;
+      message = "Error creating thread";
+      goto error;
+    }
+
+  /* For thread priority inheritance we need to manually set the thread
+   * priority of the new thread to the priority of the current thread. We
+   * also have to start the thread suspended and resume it after actually
+   * setting the priority here.
+   *
+   * On Windows, by default all new threads are created with NORMAL thread
+   * priority.
+   */
+
+  current_thread = GetCurrentThread ();
+  current_prio = GetThreadPriority (current_thread);
+  if (current_prio == THREAD_PRIORITY_ERROR_RETURN)
+    {
+      message = "Error getting current thread priority";
+      goto error;
+    }
+
+  if (SetThreadPriority (thread->handle, current_prio) == 0)
+    {
+      message = "Error setting new thread priority";
+      goto error;
+    }
+
+  if (ResumeThread (thread->handle) == -1)
+    {
+      message = "Error resuming new thread";
+      goto error;
     }
 
   return (GRealThread *) thread;
+
+error:
+  {
+    gchar *win_error = g_win32_error_message (GetLastError ());
+    g_set_error (error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN,
+                 "%s: %s", message, win_error);
+    g_free (win_error);
+    if (thread->handle)
+      CloseHandle (thread->handle);
+    g_slice_free (GThreadWin32, thread);
+    return NULL;
+  }
 }
 
 void
diff --git a/glib/gthread.c b/glib/gthread.c
index f8989009a..919b3adf5 100644
--- a/glib/gthread.c
+++ b/glib/gthread.c
@@ -833,6 +833,14 @@ g_thread_proxy (gpointer data)
  * To free the struct returned by this function, use g_thread_unref().
  * Note that g_thread_join() implicitly unrefs the #GThread as well.
  *
+ * New threads by default inherit their scheduler policy (POSIX) or thread
+ * priority (Windows) of the thread creating the new thread.
+ *
+ * This behaviour changed in GLib 2.64: before threads on Windows were not
+ * inheriting the thread priority but were spawned with the default priority.
+ * Starting with GLib 2.64 the behaviour is now consistent between Windows and
+ * POSIX and all threads inherit their parent thread's priority.
+ *
  * Returns: the new #GThread
  *
  * Since: 2.32


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]