title: How to stop g_main_loop_run properly?
body: <p>I am using GLib for the first time. So, to understand how to use GLib APIs, I wrote following dummy program.</p>
  
  <pre><code>#include&lt;glib.h&gt;
  
  #include&lt;iostream&gt;
  #include&lt;thread&gt;
  #include&lt;chrono&gt;
  
  using namespace std;
  using namespace std::chrono_literals;
  
  class executor
  {
  private:
          GMainLoop* main_loop;
          GMainContext* worker_context;
          thread worker_thread;
  
          void worker_loop()
          {
                  g_main_context_push_thread_default(worker_context);
                  cout &lt;&lt; "Starting main loop" &lt;&lt; endl;
                  g_main_loop_run(main_loop);
                  cout &lt;&lt; "Finished main loop" &lt;&lt; endl;
                  g_main_context_pop_thread_default(worker_context);
          }
  
  public:
          executor()
          {
                  worker_context = g_main_context_new();
                  main_loop = g_main_loop_new(worker_context, false);
                  worker_thread = thread(&amp;executor::worker_loop, this);
          }
  
          ~executor()
          {
                  g_main_loop_quit(main_loop);
                  cout &lt;&lt; "Stopped main loop from running" &lt;&lt; endl;
                  g_main_loop_unref(main_loop);
                  g_main_context_unref(worker_context);
                  if (worker_thread.joinable())
                  {
                          worker_thread.join();
                  }
          }
  
          void queue_callback(int (*callback)(void))
          {
                  GSource* idle_source = g_idle_source_new();
                  g_source_set_callback(idle_source, (GSourceFunc)callback, NULL, NULL);
                  g_source_attach(idle_source, worker_context);
                  g_source_unref(idle_source);
          }
  };
  
  int func1()
  {
          cout &lt;&lt; "func1 started" &lt;&lt; endl;
          this_thread::sleep_for(5s);
          cout &lt;&lt; "func1 finished waiting" &lt;&lt; endl;
          return 0;
  }
  
  int func2()
  {
          cout &lt;&lt; "func2 started" &lt;&lt; endl;
          this_thread::sleep_for(1s);
          cout &lt;&lt; "func2 finished waiting" &lt;&lt; endl;
          return 0;
  }
  
  int main()
  {
          executor e;
          e.queue_callback(func1);
          e.queue_callback(func2);
          return 0;
  }
  </code></pre>
  
  <p>When I run the program, it does not finish executing, it gets stuck. This is the output it prints.</p>
  
  <pre><code>Stopped main loop from running
  Starting main loop
  func1 started
  func1 finished waiting
  func2 started
  func2 finished waiting
  </code></pre>
  
  <p>Sometimes it just fails with following error</p>
  
  <pre><code>Stopped main loop from running
  Starting main loop
  
  (process:16343): GLib-CRITICAL **: 10:58:54.405: g_main_loop_run: assertion 'g_atomic_int_get (&amp;loop-&gt;ref_count) &gt; 0' failed
  Finished main loop
  </code></pre>
  
  <p>My guess is these both problems are happening because <code>g_main_loop_quit</code> and <code>g_main_loop_unref</code> run before <code>g_main_loop_run</code>. How do I fix these issues?</p>
  
  <p><strong>EDIT after user7860670's comment:</strong>
  Thanks to user7860670 for the suggestion. Here is the working code now.</p>
  
  <pre><code>#include&lt;glib.h&gt;
  
  #include&lt;iostream&gt;
  #include&lt;thread&gt;
  #include&lt;chrono&gt;
  
  using namespace std;
  using namespace std::chrono_literals;
  
  class executor
  {
  private:
          GMainLoop* main_loop;
          GMainContext* worker_context;
          thread worker_thread;
  
          void worker_loop()
          {
                  g_main_context_push_thread_default(worker_context);
                  cout &lt;&lt; "Starting main loop" &lt;&lt; endl;
                  g_main_loop_run(main_loop);
                  cout &lt;&lt; "Finished main loop" &lt;&lt; endl;
                  g_main_context_pop_thread_default(worker_context);
          }
  
  public:
          executor()
          {
                  worker_context = g_main_context_new();
                  main_loop = g_main_loop_new(worker_context, false);
                  worker_thread = thread(&amp;executor::worker_loop, this);
          }
  
          ~executor()
          {
                  cout &lt;&lt; "Stopping main loop" &lt;&lt; endl;
                  GSource* idle_source = g_idle_source_new();
                  g_source_set_callback(idle_source, (GSourceFunc)g_main_loop_quit, main_loop, NULL);
                  g_source_attach(idle_source, worker_context);
                  g_source_unref(idle_source);
  
                  if (worker_thread.joinable())
                  {
                          worker_thread.join();
                  }
                  cout &lt;&lt; "Removing references to main loop and context" &lt;&lt; endl;
  
                  g_main_loop_unref(main_loop);
                  g_main_context_unref(worker_context);
          }
  
          void queue_callback(int (*callback)(void))
          {
                  GSource* idle_source = g_idle_source_new();
                  g_source_set_callback(idle_source, (GSourceFunc)callback, NULL, NULL);
                  g_source_attach(idle_source, worker_context);
                  g_source_unref(idle_source);
          }
  };
  
  int func1()
  {
          cout &lt;&lt; "func1 started" &lt;&lt; endl;
          this_thread::sleep_for(5s);
          cout &lt;&lt; "func1 finished waiting" &lt;&lt; endl;
          return 0;
  }
  
  int func2()
  {
          cout &lt;&lt; "func2 started" &lt;&lt; endl;
          this_thread::sleep_for(1s);
          cout &lt;&lt; "func2 finished waiting" &lt;&lt; endl;
          return 0;
  }
  
  int main()
  {
          executor e;
          e.queue_callback(func1);
          e.queue_callback(func2);
          return 0;
  }
  </code></pre>