gem-graph-client/doc/GTK-docs/gnome-dev-documentation/developer.gnome.org/documentation/tutorials/main-contexts.html

981 lines
100 KiB
HTML
Raw Normal View History

<!doctype html>
<html class="no-js">
<head><meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="color-scheme" content="light dark"><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<link rel="index" title="Index" href="../genindex.html" /><link rel="search" title="Search" href="../search.html" /><link rel="next" title="Using GLib Lists" href="lists.html" /><link rel="prev" title="Pre- and Post-Conditions" href="pre-and-post-conditions.html" />
<meta name="generator" content="sphinx-4.3.0, furo 2022.06.21"/>
<title>Main Contexts - GNOME Developer Documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/styles/furo.css?digest=40978830699223671f4072448e654b5958f38b89" />
<link rel="stylesheet" type="text/css" href="../_static/tabs.css" />
<link rel="stylesheet" type="text/css" href="../_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
<link rel="stylesheet" type="text/css" href="../_static/gnome.css" />
<style>
body {
--color-code-background: #f8f8f8;
--color-code-foreground: black;
--color-brand-primary: #4a86cf;
--color-brand-content: #4a86cf;
}
@media not print {
body[data-theme="dark"] {
--color-code-background: #202020;
--color-code-foreground: #d0d0d0;
}
@media (prefers-color-scheme: dark) {
body:not([data-theme="light"]) {
--color-code-background: #202020;
--color-code-foreground: #d0d0d0;
}
}
}
</style></head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-toc" viewBox="0 0 24 24">
<title>Contents</title>
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 1024 1024">
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM115.4 518.9L271.7 642c5.8 4.6 14.4.5 14.4-6.9V388.9c0-7.4-8.5-11.5-14.4-6.9L115.4 505.1a8.74 8.74 0 0 0 0 13.8z"/>
</svg>
</symbol>
<symbol id="svg-menu" viewBox="0 0 24 24">
<title>Menu</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-menu">
<line x1="3" y1="12" x2="21" y2="12"></line>
<line x1="3" y1="6" x2="21" y2="6"></line>
<line x1="3" y1="18" x2="21" y2="18"></line>
</svg>
</symbol>
<symbol id="svg-arrow-right" viewBox="0 0 24 24">
<title>Expand</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-chevron-right">
<polyline points="9 18 15 12 9 6"></polyline>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24">
<title>Light mode</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="feather-sun">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24">
<title>Dark mode</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-moon">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" />
</svg>
</symbol>
<symbol id="svg-sun-half" viewBox="0 0 24 24">
<title>Auto light/dark mode</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-shadow">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<circle cx="12" cy="12" r="9" />
<path d="M13 12h5" />
<path d="M13 15h4" />
<path d="M13 18h1" />
<path d="M13 9h4" />
<path d="M13 6h1" />
</svg>
</symbol>
</svg>
<input type="checkbox" class="sidebar-toggle" name="__navigation" id="__navigation">
<input type="checkbox" class="sidebar-toggle" name="__toc" id="__toc">
<label class="overlay sidebar-overlay" for="__navigation"></label>
<label class="overlay toc-overlay" for="__toc"></label>
<div class="page">
<header class="mobile-header">
<div class="header-left">
<label class="nav-overlay-icon" for="__navigation">
<i class="icon"><svg><use href="#svg-menu"></use></svg></i>
</label>
</div>
<div class="header-center">
<a href="../index.html"><div class="brand">GNOME Developer Documentation</div></a>
</div>
<div class="header-right">
<label class="toc-overlay-icon toc-header-icon" for="__toc">
<i class="icon"><svg><use href="#svg-toc"></use></svg></i>
</label>
</div>
</header>
<aside class="sidebar-drawer">
<div class="sidebar-container">
<div class="sidebar-sticky"><a class="sidebar-brand" href="../index.html">
<span class="sidebar-brand-text">GNOME Developer Documentation</span>
</a><form class="sidebar-search-container" method="get" action="../search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
<input type="hidden" name="check_keywords" value="yes">
<input type="hidden" name="area" value="default">
</form>
<div id="searchbox"></div><div class="sidebar-scroll"><div class="sidebar-tree">
<p class="caption" role="heading"><span class="caption-text">Contents</span></p>
<ul class="current">
<li class="toctree-l1 has-children"><a class="reference internal" href="../introduction.html">Platform Introduction</a><input class="toctree-checkbox" id="toctree-checkbox-1" name="toctree-checkbox-1" role="switch" type="checkbox"/><label for="toctree-checkbox-1"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2 has-children"><a class="reference internal" href="../introduction/components.html">Platform Components</a><input class="toctree-checkbox" id="toctree-checkbox-2" name="toctree-checkbox-2" role="switch" type="checkbox"/><label for="toctree-checkbox-2"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l3"><a class="reference internal" href="../introduction/overview/libraries.html">Libraries</a></li>
<li class="toctree-l3"><a class="reference internal" href="../introduction/overview/services.html">Services</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../introduction/languages.html">Programming Languages</a></li>
<li class="toctree-l2"><a class="reference internal" href="../introduction/builder.html">GNOME Builder</a></li>
<li class="toctree-l2"><a class="reference internal" href="../introduction/flatpak.html">Flatpak</a></li>
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../guidelines.html">Guidelines</a><input class="toctree-checkbox" id="toctree-checkbox-3" name="toctree-checkbox-3" role="switch" type="checkbox"/><label for="toctree-checkbox-3"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2 has-children"><a class="reference internal" href="../guidelines/programming.html">Programming Guidelines</a><input class="toctree-checkbox" id="toctree-checkbox-4" name="toctree-checkbox-4" role="switch" type="checkbox"/><label for="toctree-checkbox-4"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l3"><a class="reference internal" href="../guidelines/programming/coding-style.html">C Coding Style</a></li>
<li class="toctree-l3"><a class="reference internal" href="../guidelines/programming/memory-management.html">Managing Memory</a></li>
<li class="toctree-l3"><a class="reference internal" href="../guidelines/programming/writing-good-code.html">The Importance of Writing Good Code</a></li>
<li class="toctree-l3"><a class="reference internal" href="../guidelines/programming/optimizing.html">Optimizing GNOME Applications</a></li>
<li class="toctree-l3"><a class="reference internal" href="../guidelines/programming/namespacing.html">Namespacing</a></li>
<li class="toctree-l3"><a class="reference internal" href="../guidelines/programming/introspection.html">Introspection</a></li>
</ul>
</li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../guidelines/accessibility.html">Accessibility</a><input class="toctree-checkbox" id="toctree-checkbox-5" name="toctree-checkbox-5" role="switch" type="checkbox"/><label for="toctree-checkbox-5"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l3"><a class="reference internal" href="../guidelines/accessibility/coding-guidelines.html">Coding Guidelines for Supporting Accessibility</a></li>
<li class="toctree-l3"><a class="reference internal" href="../guidelines/accessibility/custom-widgets.html">Making Custom Components Accessible</a></li>
</ul>
</li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../guidelines/localization.html">Localization</a><input class="toctree-checkbox" id="toctree-checkbox-6" name="toctree-checkbox-6" role="switch" type="checkbox"/><label for="toctree-checkbox-6"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l3"><a class="reference internal" href="../guidelines/localization/practices.html">Best Practices for Localization</a></li>
</ul>
</li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../guidelines/maintainer.html">Maintainer Guidelines</a><input class="toctree-checkbox" id="toctree-checkbox-7" name="toctree-checkbox-7" role="switch" type="checkbox"/><label for="toctree-checkbox-7"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l3"><a class="reference internal" href="../guidelines/maintainer/api-stability.html">API Stability</a></li>
<li class="toctree-l3"><a class="reference internal" href="../guidelines/maintainer/parallel-installability.html">Parallel Installability</a></li>
<li class="toctree-l3"><a class="reference internal" href="../guidelines/maintainer/integrating.html">Integrating with GNOME</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../guidelines/devel-docs.html">Developer Documentation Style Guidelines</a></li>
</ul>
</li>
<li class="toctree-l1 current has-children"><a class="reference internal" href="../tutorials.html">Tutorials</a><input checked="" class="toctree-checkbox" id="toctree-checkbox-8" name="toctree-checkbox-8" role="switch" type="checkbox"/><label for="toctree-checkbox-8"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="current">
<li class="toctree-l2 has-children"><a class="reference internal" href="beginners.html">Beginners Tutorials</a><input class="toctree-checkbox" id="toctree-checkbox-9" name="toctree-checkbox-9" role="switch" type="checkbox"/><label for="toctree-checkbox-9"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l3 has-children"><a class="reference internal" href="beginners/getting_started.html">Getting Started</a><input class="toctree-checkbox" id="toctree-checkbox-10" name="toctree-checkbox-10" role="switch" type="checkbox"/><label for="toctree-checkbox-10"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l4"><a class="reference internal" href="beginners/getting_started/content_view.html">Adding A Content View</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/getting_started/opening_files.html">Loading Content From A File</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/getting_started/cursor_position.html">Showing The Cursor Position</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/getting_started/saving_files.html">Saving The Content To A File</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/getting_started/saving_state.html">Saving The Application State</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/getting_started/adding_toasts.html">Notifying The User With Toasts</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/getting_started/dark_mode.html">Forcing The Dark Color Scheme</a></li>
</ul>
</li>
<li class="toctree-l3 has-children"><a class="reference internal" href="beginners/components.html">UI components</a><input class="toctree-checkbox" id="toctree-checkbox-11" name="toctree-checkbox-11" role="switch" type="checkbox"/><label for="toctree-checkbox-11"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/window.html">Windows</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/image.html">Images</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/label.html">Labels</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/button.html">Buttons</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/box.html">Boxes</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/stack.html">Stacks</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/leaflet.html">Leaflets</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/toggle.html">Toggles</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/check_box.html">Check Boxes</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/radio_button.html">Radio Buttons</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/spin_button.html">Spin Buttons</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/link_button.html">Link Buttons</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/switch.html">Switches</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/menu_button.html">Menu Buttons</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/entry.html">Entries</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/password_entry.html">Password Entries</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/message_dialog.html">Messages</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/file_dialog.html">File Dialogs</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/spinner.html">Spinners</a></li>
<li class="toctree-l4"><a class="reference internal" href="beginners/components/level_bar.html">Level Bars</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="application-id.html">Application ID</a></li>
<li class="toctree-l2"><a class="reference internal" href="application.html">Using GtkApplication</a></li>
<li class="toctree-l2"><a class="reference internal" href="save-state.html">Saving and Loading Window State</a></li>
<li class="toctree-l2"><a class="reference internal" href="notifications.html">Using Notifications</a></li>
<li class="toctree-l2"><a class="reference internal" href="themed-icons.html">Themed Icons</a></li>
<li class="toctree-l2"><a class="reference internal" href="deprecations.html">Dealing With Deprecations</a></li>
<li class="toctree-l2"><a class="reference internal" href="actions.html">Actions</a></li>
<li class="toctree-l2"><a class="reference internal" href="menus.html">Menus</a></li>
<li class="toctree-l2"><a class="reference internal" href="search-provider.html">Writing a Search Provider</a></li>
<li class="toctree-l2"><a class="reference internal" href="pre-and-post-conditions.html">Pre- and Post-Conditions</a></li>
<li class="toctree-l2 current current-page"><a class="current reference internal" href="#">Main Contexts</a></li>
<li class="toctree-l2"><a class="reference internal" href="lists.html">Using GLib Lists</a></li>
<li class="toctree-l2"><a class="reference internal" href="threading.html">Threading</a></li>
<li class="toctree-l2"><a class="reference internal" href="asynchronous-programming.html">Asynchronous Programming</a></li>
<li class="toctree-l2"><a class="reference internal" href="drag-and-drop.html">Drag and Drop</a></li>
<li class="toctree-l2"><a class="reference internal" href="widget-templates.html">Widget Templates</a></li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="content">
<article role="main">
<label class="toc-overlay-icon toc-content-icon" for="__toc">
<i class="icon"><svg><use href="#svg-toc"></use></svg></i>
</label>
<section id="main-contexts">
<h1>Main Contexts<a class="headerlink" href="#main-contexts" title="Permalink to this headline">#</a></h1>
<section id="summary">
<h2>Summary<a class="headerlink" href="#summary" title="Permalink to this headline">#</a></h2>
<ul class="simple">
<li><p>Use <code class="docutils literal notranslate"><span class="pre">g_main_context_invoke_full()</span></code> to invoke functions in other threads,
assuming every thread has a thread default main context which runs throughout
the lifetime of that thread</p></li>
<li><p>Use <code class="docutils literal notranslate"><span class="pre">GTask</span></code> to run a function in the background without caring about the
specific thread used</p></li>
<li><p>Liberally use assertions to check which context executes each function, and
add these assertions when first writing the code</p></li>
<li><p>Explicitly document contexts a function is expected to be called in, a
callback will be invoked in, or a signal will be emitted in</p></li>
<li><p>Beware of <code class="docutils literal notranslate"><span class="pre">g_idle_add()</span></code> and similar functions which implicitly use the
global-default main context</p></li>
</ul>
</section>
<section id="what-is-gmaincontext">
<h2>What is GMainContext?<a class="headerlink" href="#what-is-gmaincontext" title="Permalink to this headline">#</a></h2>
<p><code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> is a generalized implementation of an event loop, useful for
implementing polled file I/O or event-based widget systems (such as GTK). It is
at the core of almost every GLib application. To understand <code class="docutils literal notranslate"><span class="pre">GMainContext</span></code>
requires understanding <code class="docutils literal notranslate"><span class="pre">poll()</span></code> and polled I/O.</p>
<p>A <code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> has a set of sources which are attached to it, each of
which can be thought of as an expected event with an associated callback
function which will be invoked when that event is received; or equivalently as a
set of file descriptors (FDs) to check. An event could be a timeout or data
being received on a socket, for example. One iteration of the event loop will:</p>
<ul class="simple">
<li><p>Prepare sources, determining if any of them are ready to dispatch immediately.</p></li>
<li><p>Poll the sources, blocking the current thread until an event is received for
one of the sources.</p></li>
<li><p>Check which of the sources received an event (several could have).</p></li>
<li><p>Dispatch callbacks from those sources.</p></li>
</ul>
<p>This is explained very well in the <a class="reference external" href="https://docs.gtk.org/glib/main-loop.html">GLib documentation</a>.</p>
<p>At its core, <code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> is just a <code class="docutils literal notranslate"><span class="pre">poll()</span></code> loop, with the preparation,
check and dispatch stages of the loop corresponding to the normal preamble and
postamble in a typical <code class="docutils literal notranslate"><span class="pre">poll()</span></code> loop implementation. Typically, some
complexity is needed in non-trivial <code class="docutils literal notranslate"><span class="pre">poll()</span></code>-using applications to track the
lists of FDs which are being polled. Additionally, <code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> adds a lot
of useful functionality which vanilla <code class="docutils literal notranslate"><span class="pre">poll()</span></code> doesnt support. Most
importantly, it adds thread safety.</p>
<p><code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> is completely thread safe, meaning that a <code class="docutils literal notranslate"><span class="pre">GSource</span></code> can be
created in one thread and attached to a <code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> running in another
thread. A typical use for this might be to allow worker threads to control which
sockets are being listened to by a <code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> in a central I/O thread.
Each <code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> is acquired by a thread for each iteration its put
through. Other threads cannot iterate a <code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> without acquiring it,
which guarantees that a <code class="docutils literal notranslate"><span class="pre">GSource</span></code> and its FDs will only be polled by one
thread at once (since each <code class="docutils literal notranslate"><span class="pre">GSource</span></code> is attached to at most one
<code class="docutils literal notranslate"><span class="pre">GMainContext</span></code>). A <code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> can be swapped between threads across
iterations, but this is expensive.</p>
<p><code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> is used instead of <code class="docutils literal notranslate"><span class="pre">poll()</span></code> mostly for convenience, as it
transparently handles dynamically managing the array of FDs to pass to
<code class="docutils literal notranslate"><span class="pre">poll()</span></code>, especially when operating over multiple threads. This is done by
encapsulating file descriptors inside a <code class="docutils literal notranslate"><span class="pre">GSource</span></code>, which decide whether those
FDs should be passed to the <code class="docutils literal notranslate"><span class="pre">poll()</span></code> call on each prepare stage of the main
context iteration.</p>
</section>
<section id="what-is-gmainloop">
<h2>What is GMainLoop?<a class="headerlink" href="#what-is-gmainloop" title="Permalink to this headline">#</a></h2>
<p><code class="docutils literal notranslate"><span class="pre">GMainLoop</span></code> is essentially the following few lines of code, once reference
counting and locking have been removed:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">loop</span><span class="o">-&gt;</span><span class="n">is_running</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">TRUE</span><span class="p">;</span><span class="w"></span>
<span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">loop</span><span class="o">-&gt;</span><span class="n">is_running</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">quit_condition</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="n">loop</span><span class="o">-&gt;</span><span class="n">is_running</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">FALSE</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_context_iteration</span><span class="w"> </span><span class="p">(</span><span class="n">context</span><span class="p">,</span><span class="w"> </span><span class="n">TRUE</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>Setting <code class="docutils literal notranslate"><span class="pre">quit_condition</span></code> to <code class="docutils literal notranslate"><span class="pre">TRUE</span></code> will cause the loop to terminate once the
current main context iteration ends.</p>
<p>Hence, <code class="docutils literal notranslate"><span class="pre">GMainLoop</span></code> is a convenient, thread-safe way of running a
<code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> to process events until a desired exit condition is met, at
which point <code class="docutils literal notranslate"><span class="pre">g_main_loop_quit()</span></code> should be called. Typically, in a UI program,
this will be the user clicking exit. In a socket handling program, this might
be the final socket closing.</p>
<p>It is important not to confuse main contexts with main loops. Main contexts do
the bulk of the work: preparing source lists, waiting for events, and
dispatching callbacks. A main loop simply iterates a context.</p>
</section>
<section id="default-contexts">
<h2>Default Contexts<a class="headerlink" href="#default-contexts" title="Permalink to this headline">#</a></h2>
<p>One of the important features of <code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> is its support for default
contexts. There are two levels of default context: the thread-default, and the
global-default. The global-default (accessed using <code class="docutils literal notranslate"><span class="pre">g_main_context_default()</span></code>) is
run by GTK when <code class="docutils literal notranslate"><span class="pre">g_application_run()</span></code> is called. Its also used for timeouts
(<code class="docutils literal notranslate"><span class="pre">g_timeout_add()</span></code>) and idle callbacks (<code class="docutils literal notranslate"><span class="pre">g_idle_add()</span></code>) — these wont be dispatched
unless the default context is running!</p>
<p>Thread-default contexts are generally used for I/O operations which need to run
and dispatch callbacks in a thread. By calling
<code class="docutils literal notranslate"><span class="pre">g_main_context_push_thread_default()</span></code> before starting an I/O operation, the
thread-default context is set and the I/O operation can add its sources to that
context. The context can then be run in a new main loop in an I/O thread,
causing the callbacks to be dispatched on that threads stack rather than on the
stack of the thread running the global-default main context. This allows I/O
operations to be run entirely in a separate thread without explicitly passing a
specific GMainContext pointer around everywhere.</p>
<p>Conversely, by starting a long-running operation with a specific thread-default
context set, the calling code can guarantee that the operations callbacks will
be emitted in that context, even if the operation itself runs in a worker
thread. This is the principle behind <code class="docutils literal notranslate"><span class="pre">GTask</span></code>: when a new <code class="docutils literal notranslate"><span class="pre">GTask</span></code> is created, it
stores a reference to the current thread-default context, and dispatches its
completion callback in that context, even if the task itself is run using
<code class="docutils literal notranslate"><span class="pre">g_task_run_in_thread()</span></code>.</p>
<p>For example, the code below will run a <code class="docutils literal notranslate"><span class="pre">GTask</span></code> which performs two writes in
parallel from a thread. The callbacks for the writes will be dispatched in the
worker thread, whereas the callback from the task as a whole will be dispatched
in the interesting_context.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">GMainLoop</span><span class="w"> </span><span class="o">*</span><span class="n">main_loop</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">guint</span><span class="w"> </span><span class="n">n_remaining</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"> </span><span class="n">WriteData</span><span class="p">;</span><span class="w"></span>
<span class="cm">/* This is always called in the same thread as thread_cb() because</span>
<span class="cm"> * its always dispatched in the @worker_context. */</span><span class="w"></span>
<span class="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">write_cb</span><span class="w"> </span><span class="p">(</span><span class="n">GObject</span><span class="w"> </span><span class="o">*</span><span class="n">source_object</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">GAsyncResult</span><span class="w"> </span><span class="o">*</span><span class="n">result</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">gpointer</span><span class="w"> </span><span class="n">user_data</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">WriteData</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">user_data</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GOutputStream</span><span class="w"> </span><span class="o">*</span><span class="n">stream</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">G_OUTPUT_STREAM</span><span class="w"> </span><span class="p">(</span><span class="n">source_object</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">GError</span><span class="w"> </span><span class="o">*</span><span class="n">error</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">gssize</span><span class="w"> </span><span class="n">len</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Finish the write. */</span><span class="w"></span>
<span class="w"> </span><span class="n">len</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_output_stream_write_finish</span><span class="w"> </span><span class="p">(</span><span class="n">stream</span><span class="p">,</span><span class="w"> </span><span class="n">result</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">error</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">error</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">g_error</span><span class="w"> </span><span class="p">(</span><span class="s">&quot;Error: %s&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">error</span><span class="o">-&gt;</span><span class="n">message</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_error_free</span><span class="w"> </span><span class="p">(</span><span class="n">error</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Check whether all parallel operations have finished. */</span><span class="w"></span>
<span class="w"> </span><span class="n">write_data</span><span class="o">-&gt;</span><span class="n">n_remaining</span><span class="o">--</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">write_data</span><span class="o">-&gt;</span><span class="n">n_remaining</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_loop_quit</span><span class="w"> </span><span class="p">(</span><span class="n">write_data</span><span class="o">-&gt;</span><span class="n">main_loop</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="cm">/* This is called in a new thread. */</span><span class="w"></span>
<span class="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">thread_cb</span><span class="w"> </span><span class="p">(</span><span class="n">GTask</span><span class="w"> </span><span class="o">*</span><span class="n">task</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">gpointer</span><span class="w"> </span><span class="n">source_object</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">gpointer</span><span class="w"> </span><span class="n">task_data</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">GCancellable</span><span class="w"> </span><span class="o">*</span><span class="n">cancellable</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* These streams come from somewhere else in the program: */</span><span class="w"></span>
<span class="w"> </span><span class="n">GOutputStream</span><span class="w"> </span><span class="o">*</span><span class="n">output_stream1</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">output_stream</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GMainContext</span><span class="w"> </span><span class="o">*</span><span class="n">worker_context</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GBytes</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">guint8</span><span class="w"> </span><span class="o">*</span><span class="n">buf</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">gsize</span><span class="w"> </span><span class="n">len</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Set up a worker context for the writes callbacks. */</span><span class="w"></span>
<span class="w"> </span><span class="n">worker_context</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_main_context_new</span><span class="w"> </span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_context_push_thread_default</span><span class="w"> </span><span class="p">(</span><span class="n">worker_context</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Set up the writes. */</span><span class="w"></span>
<span class="w"> </span><span class="n">write_data</span><span class="p">.</span><span class="n">n_remaining</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">2</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">write_data</span><span class="p">.</span><span class="n">main_loop</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_main_loop_new</span><span class="w"> </span><span class="p">(</span><span class="n">worker_context</span><span class="p">,</span><span class="w"> </span><span class="n">FALSE</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_task_get_task_data</span><span class="w"> </span><span class="p">(</span><span class="n">task</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">buf</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_bytes_get_data</span><span class="w"> </span><span class="p">(</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">len</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_output_stream_write_async</span><span class="w"> </span><span class="p">(</span><span class="n">output_stream1</span><span class="p">,</span><span class="w"> </span><span class="n">buf</span><span class="p">,</span><span class="w"> </span><span class="n">len</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">G_PRIORITY_DEFAULT</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">write_cb</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="o">&amp;</span><span class="n">write_data</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_output_stream_write_async</span><span class="w"> </span><span class="p">(</span><span class="n">output_stream2</span><span class="p">,</span><span class="w"> </span><span class="n">buf</span><span class="p">,</span><span class="w"> </span><span class="n">len</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">G_PRIORITY_DEFAULT</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">write_cb</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="o">&amp;</span><span class="n">write_data</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Run the main loop until both writes have finished. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_loop_run</span><span class="w"> </span><span class="p">(</span><span class="n">write_data</span><span class="p">.</span><span class="n">main_loop</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_task_return_boolean</span><span class="w"> </span><span class="p">(</span><span class="n">task</span><span class="p">,</span><span class="w"> </span><span class="n">TRUE</span><span class="p">);</span><span class="w"> </span><span class="cm">/* ignore errors */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_loop_unref</span><span class="w"> </span><span class="p">(</span><span class="n">write_data</span><span class="p">.</span><span class="n">main_loop</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_context_pop_thread_default</span><span class="w"> </span><span class="p">(</span><span class="n">worker_context</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_context_unref</span><span class="w"> </span><span class="p">(</span><span class="n">worker_context</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="cm">/* This can be called from any thread. Its @callback will always be</span>
<span class="cm"> * dispatched in the thread which currently owns</span>
<span class="cm"> * @interesting_context. */</span><span class="w"></span>
<span class="kt">void</span><span class="w"></span>
<span class="nf">parallel_writes_async</span><span class="w"> </span><span class="p">(</span><span class="n">GBytes</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">GMainContext</span><span class="w"> </span><span class="o">*</span><span class="n">interesting_context</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">GCancellable</span><span class="w"> </span><span class="o">*</span><span class="n">cancellable</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">GAsyncReadyCallback</span><span class="w"> </span><span class="n">callback</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">gpointer</span><span class="w"> </span><span class="n">user_data</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">GTask</span><span class="w"> </span><span class="o">*</span><span class="n">task</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_context_push_thread_default</span><span class="w"> </span><span class="p">(</span><span class="n">interesting_context</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">task</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_task_new</span><span class="w"> </span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">cancellable</span><span class="p">,</span><span class="w"> </span><span class="n">callback</span><span class="p">,</span><span class="w"> </span><span class="n">user_data</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_task_set_task_data</span><span class="w"> </span><span class="p">(</span><span class="n">task</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="n">GDestroyNotify</span><span class="p">)</span><span class="w"> </span><span class="n">g_bytes_unref</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_task_run_in_thread</span><span class="w"> </span><span class="p">(</span><span class="n">task</span><span class="p">,</span><span class="w"> </span><span class="n">thread_cb</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_object_unref</span><span class="w"> </span><span class="p">(</span><span class="n">task</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_context_pop_thread_default</span><span class="w"> </span><span class="p">(</span><span class="n">interesting_context</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
</section>
<section id="implicit-use-of-the-global-default-main-context">
<h2>Implicit Use of the Global-Default Main Context<a class="headerlink" href="#implicit-use-of-the-global-default-main-context" title="Permalink to this headline">#</a></h2>
<p>Several functions implicitly add sources to the global-default main context.
They should not be used in threaded code. Instead, use <code class="docutils literal notranslate"><span class="pre">g_source_attach()</span></code>
with the <code class="docutils literal notranslate"><span class="pre">GSource</span></code> created by the replacement function from the table below.</p>
<p>Implicit use of the global-default main context means the callback functions are
invoked in the main thread, typically resulting in work being brought back from
a worker thread into the main thread.</p>
<div class="table-wrapper colwidths-given docutils container">
<table class="colwidths-given docutils align-default">
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>Do not use</p></th>
<th class="head"><p>Use instead</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">g_timeout_add()</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">g_timeout_source_new()</span></code></p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">g_idle_add()</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">g_idle_source_new()</span></code></p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">g_child_watch_add()</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">g_child_watch_source_new()</span></code></p></td>
</tr>
</tbody>
</table>
</div>
<p>So to delay some computation in a worker thread, use the following code:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="n">guint</span><span class="w"></span>
<span class="nf">schedule_computation</span><span class="w"> </span><span class="p">(</span><span class="n">guint</span><span class="w"> </span><span class="n">delay_seconds</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Get the calling context. */</span><span class="w"></span>
<span class="w"> </span><span class="n">GMainContext</span><span class="w"> </span><span class="o">*</span><span class="n">context</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_main_context_get_thread_default</span><span class="w"> </span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">GSource</span><span class="w"> </span><span class="o">*</span><span class="n">source</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_timeout_source_new_seconds</span><span class="w"> </span><span class="p">(</span><span class="n">delay_seconds</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_source_set_callback</span><span class="w"> </span><span class="p">(</span><span class="n">source</span><span class="p">,</span><span class="w"> </span><span class="n">do_computation</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">guint</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_source_attach</span><span class="w"> </span><span class="p">(</span><span class="n">source</span><span class="p">,</span><span class="w"> </span><span class="n">context</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_source_unref</span><span class="w"> </span><span class="p">(</span><span class="n">source</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* The ID can be used with the same @context to</span>
<span class="cm"> * cancel the scheduled computation if needed. */</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">id</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">do_computation</span><span class="w"> </span><span class="p">(</span><span class="n">gpointer</span><span class="w"> </span><span class="n">user_data</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="c1">// ...</span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
</section>
<section id="using-gmaincontext-in-a-library">
<h2>Using GMainContext in a Library<a class="headerlink" href="#using-gmaincontext-in-a-library" title="Permalink to this headline">#</a></h2>
<p>At a high level, library code must not make changes to main contexts which could
affect the execution of an application using the library, for example by
changing when the applications sources are dispatched. There are various best
practices which can be followed to aid this.</p>
<p>Never iterate a context created outside the library, including the
global-default or thread-default contexts. Otherwise, sources created in the
application may be dispatched when the application is not expecting it, causing
re-entrancy problems for the application code.</p>
<p>Always remove sources from a main context before dropping the librarys last
reference to the context, especially if it may have been exposed to the
application (for example, as a thread-default). Otherwise the application may
keep a reference to the main context and continue iterating it after the library
has returned, potentially causing unexpected source dispatches in the library.
This is equivalent to not assuming that dropping the librarys last reference to
a main context will finalize that context.</p>
<p>If the library is designed to be used from multiple threads, or in a
context-aware fashion, always document which context each callback will be
dispatched in. For example, “callbacks will always be dispatched in the context
which is the thread-default at the time of the objects construction”.
Developers using the librarys API need to know this information.</p>
<p>Use <code class="docutils literal notranslate"><span class="pre">g_main_context_invoke()</span></code> to ensure callbacks are dispatched in the right
context. Its much easier than manually using <code class="docutils literal notranslate"><span class="pre">g_idle_source_new()</span></code> to
transfer work between contexts.</p>
<p>Libraries should never use <code class="docutils literal notranslate"><span class="pre">g_main_context_default()</span></code> (or, equivalently, pass
NULL to a <code class="docutils literal notranslate"><span class="pre">GMainContext</span></code>-typed parameter). Always store and explicitly use a
specific <code class="docutils literal notranslate"><span class="pre">GMainContext</span></code>, even if it often points to some default context. This
makes the code easier to split out into threads in future, if needed, without
causing hard-to-debug problems caused by callbacks being invoked in the wrong
context.</p>
<p>Write things asynchronously internally (using <code class="docutils literal notranslate"><span class="pre">GTask</span></code> where appropriate), and
keep synchronous wrappers at the very top level of an API, where they can be
implemented by calling <code class="docutils literal notranslate"><span class="pre">g_main_context_iteration()</span></code> on a specific
<code class="docutils literal notranslate"><span class="pre">GMainContext</span></code>. Again, this makes future refactoring easier. This is
demonstrated in the previous example: the thread uses
<code class="docutils literal notranslate"><span class="pre">g_output_stream_write_async()</span></code> rather than <code class="docutils literal notranslate"><span class="pre">g_output_stream_write()</span></code>. A
worker thread may be used instead, and this can simplify the callback chain for
long series of asynchronous calls; but at the cost of increased complexity in
verifying the code is race-free.</p>
<p>Always match pushes and pops of the thread-default main context:
<code class="docutils literal notranslate"><span class="pre">g_main_context_push_thread_default()</span></code> and
<code class="docutils literal notranslate"><span class="pre">g_main_context_pop_thread_default()</span></code>.</p>
</section>
<section id="ensuring-functions-are-called-in-the-right-context">
<h2>Ensuring Functions are Called in the Right Context<a class="headerlink" href="#ensuring-functions-are-called-in-the-right-context" title="Permalink to this headline">#</a></h2>
<p>The right context is the thread-default main context of the thread the
function should be executing in. This assumes the typical case that every thread
has a single main context running in a main loop. A main context effectively
provides a work or message queue for the thread — something which the thread can
periodically check to determine if there is work pending from another thread.
Putting a message on this queue invoking a function in another main context
will result in it eventually being dispatched in that thread.</p>
<p>For example, if an application does a long and CPU-intensive computation it
should schedule this in a background thread so that UI updates in the main
thread are not blocked. The results of the computation, however, might need to
be displayed in the UI, so some UI update function must be called in the main
thread once the computations complete.</p>
<p>Furthermore, if the computation function can be limited to a single thread, it
becomes easy to eliminate the need for locking a lot of the data it accesses.
This assumes that other threads are implemented similarly and hence most data is
only accessed by a single thread, with threads communicating by message passing.
This allows each thread to update its data at its leisure, which significantly
simplifies locking.</p>
<p>For some functions, there might be no reason to care which context theyre
executed in, perhaps because theyre asynchronous and hence do not block the
context. However, it is still advisable to be explicit about which context is
used, since those functions may emit signals or invoke callbacks, and for
reasons of thread safety its necessary to know which threads those signal
handlers or callbacks are going to be invoked in.</p>
<p>For example, the progress callback in <code class="docutils literal notranslate"><span class="pre">g_file_copy_async()</span></code> is documented as
being called in the thread-default main context at the time of the initial call.</p>
</section>
<section id="principles-of-invocation">
<h2>Principles of Invocation<a class="headerlink" href="#principles-of-invocation" title="Permalink to this headline">#</a></h2>
<p>The core principle of invoking a function in a specific context is simple, and
is walked through below to explain the concepts. In practice the convenience
method, <code class="docutils literal notranslate"><span class="pre">g_main_context_invoke_full()</span></code> should be used instead.</p>
<p>A <code class="docutils literal notranslate"><span class="pre">GSource</span></code> has to be added to the target <code class="docutils literal notranslate"><span class="pre">GMainContext</span></code>, which will invoke
the function when its dispatched. This <code class="docutils literal notranslate"><span class="pre">GSource</span></code> should almost always be an
idle source created with <code class="docutils literal notranslate"><span class="pre">g_idle_source_new()</span></code>, but this doesnt have to be
the case. It could be a timeout source so that the function is executed after a
delay, for example.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">GSource</span></code> will be dispatched as soon as its ready, calling the function
on the threads stack. In the case of an idle source, this will be as soon as
all sources at a higher priority have been dispatched — this can be tweaked
using the idle sources priority parameter with <code class="docutils literal notranslate"><span class="pre">g_source_set_priority()</span></code>. The
source will typically then be destroyed so the function is only executed once
(though again, this doesnt have to be the case).</p>
<p>Data can be passed between threads as the <code class="docutils literal notranslate"><span class="pre">user_data</span></code> passed to the
<code class="docutils literal notranslate"><span class="pre">GSource</span></code>s callback. This is set on the source using
<code class="docutils literal notranslate"><span class="pre">g_source_set_callback()</span></code>, along with the callback function to invoke. Only a
single pointer is provided, so if multiple data fields need passing, they must
be wrapped in an allocated structure.</p>
<p>The example below demonstrates the underlying principles, but there are
convenience methods explained below which simplify things.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cm">/* Main function for the background thread, thread1. */</span><span class="w"></span>
<span class="k">static</span><span class="w"> </span><span class="n">gpointer</span><span class="w"></span>
<span class="nf">thread1_main</span><span class="w"> </span><span class="p">(</span><span class="n">gpointer</span><span class="w"> </span><span class="n">user_data</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">GMainContext</span><span class="w"> </span><span class="o">*</span><span class="n">thread1_main_context</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">user_data</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GMainLoop</span><span class="w"> </span><span class="o">*</span><span class="n">main_loop</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Set up the threads context and run it forever. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_context_push_thread_default</span><span class="w"> </span><span class="p">(</span><span class="n">thread1_main_context</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">main_loop</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_main_loop_new</span><span class="w"> </span><span class="p">(</span><span class="n">thread1_main_context</span><span class="p">,</span><span class="w"> </span><span class="n">FALSE</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_loop_run</span><span class="w"> </span><span class="p">(</span><span class="n">main_loop</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_loop_unref</span><span class="w"> </span><span class="p">(</span><span class="n">main_loop</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_context_pop_thread_default</span><span class="w"> </span><span class="p">(</span><span class="n">thread1_main_context</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_context_unref</span><span class="w"> </span><span class="p">(</span><span class="n">thread1_main_context</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="cm">/* A data closure structure to carry multiple variables between</span>
<span class="cm"> * threads. */</span><span class="w"></span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">gchar</span><span class="w"> </span><span class="o">*</span><span class="n">some_string</span><span class="p">;</span><span class="w"> </span><span class="cm">/* owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">guint</span><span class="w"> </span><span class="n">some_int</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GObject</span><span class="w"> </span><span class="o">*</span><span class="n">some_object</span><span class="p">;</span><span class="w"> </span><span class="cm">/* owned */</span><span class="w"></span>
<span class="p">}</span><span class="w"> </span><span class="n">MyFuncData</span><span class="p">;</span><span class="w"></span>
<span class="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">my_func_data_free</span><span class="w"> </span><span class="p">(</span><span class="n">MyFuncData</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">g_free</span><span class="w"> </span><span class="p">(</span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_string</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_clear_object</span><span class="w"> </span><span class="p">(</span><span class="o">&amp;</span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_object</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_free</span><span class="w"> </span><span class="p">(</span><span class="n">data</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">my_func</span><span class="w"> </span><span class="p">(</span><span class="k">const</span><span class="w"> </span><span class="n">gchar</span><span class="w"> </span><span class="o">*</span><span class="n">some_string</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">guint</span><span class="w"> </span><span class="n">some_int</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">GObject</span><span class="w"> </span><span class="o">*</span><span class="n">some_object</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Do something long and CPU intensive! */</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="cm">/* Convert an idle callback into a call to my_func(). */</span><span class="w"></span>
<span class="k">static</span><span class="w"> </span><span class="n">gboolean</span><span class="w"></span>
<span class="nf">my_func_idle</span><span class="w"> </span><span class="p">(</span><span class="n">gpointer</span><span class="w"> </span><span class="n">user_data</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">MyFuncData</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">user_data</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">my_func</span><span class="w"> </span><span class="p">(</span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_string</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_int</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_object</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">G_SOURCE_REMOVE</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="cm">/* Function to be called in the main thread to schedule a call to</span>
<span class="cm"> * my_func() in thread1, passing the given parameters along. */</span><span class="w"></span>
<span class="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">invoke_my_func</span><span class="w"> </span><span class="p">(</span><span class="n">GMainContext</span><span class="w"> </span><span class="o">*</span><span class="n">thread1_main_context</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">gchar</span><span class="w"> </span><span class="o">*</span><span class="n">some_string</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">guint</span><span class="w"> </span><span class="n">some_int</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">GObject</span><span class="w"> </span><span class="o">*</span><span class="n">some_object</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">GSource</span><span class="w"> </span><span class="o">*</span><span class="n">idle_source</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">MyFuncData</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Create a data closure to pass all the desired variables</span>
<span class="cm"> * between threads. */</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_new0</span><span class="w"> </span><span class="p">(</span><span class="n">MyFuncData</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_string</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_strdup</span><span class="w"> </span><span class="p">(</span><span class="n">some_string</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_int</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">some_int</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_object</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_object_ref</span><span class="w"> </span><span class="p">(</span><span class="n">some_object</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Create a new idle source, set my_func() as the callback with</span>
<span class="cm"> * some data to be passed between threads, bump up the priority</span>
<span class="cm"> * and schedule it by attaching it to thread1s context. */</span><span class="w"></span>
<span class="w"> </span><span class="n">idle_source</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_idle_source_new</span><span class="w"> </span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">g_source_set_callback</span><span class="w"> </span><span class="p">(</span><span class="n">idle_source</span><span class="p">,</span><span class="w"> </span><span class="n">my_func_idle</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="n">GDestroyNotify</span><span class="p">)</span><span class="w"> </span><span class="n">my_func_data_free</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_source_set_priority</span><span class="w"> </span><span class="p">(</span><span class="n">idle_source</span><span class="p">,</span><span class="w"> </span><span class="n">G_PRIORITY_DEFAULT</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_source_attach</span><span class="w"> </span><span class="p">(</span><span class="n">idle_source</span><span class="p">,</span><span class="w"> </span><span class="n">thread1_main_context</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_source_unref</span><span class="w"> </span><span class="p">(</span><span class="n">idle_source</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="cm">/* Main function for the main thread. */</span><span class="w"></span>
<span class="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">main</span><span class="w"> </span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">GThread</span><span class="w"> </span><span class="o">*</span><span class="n">thread1</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GMainContext</span><span class="w"> </span><span class="o">*</span><span class="n">thread1_main_context</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Spawn a background thread and pass it a reference to its</span>
<span class="cm"> * GMainContext. Retain a reference for use in this thread</span>
<span class="cm"> * too. */</span><span class="w"></span>
<span class="w"> </span><span class="n">thread1_main_context</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_main_context_new</span><span class="w"> </span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">g_thread_new</span><span class="w"> </span><span class="p">(</span><span class="s">&quot;thread1&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">thread1_main</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_context_ref</span><span class="w"> </span><span class="p">(</span><span class="n">thread1_main_context</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Maybe set up your UI here, for example. */</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Invoke my_func() in the other thread. */</span><span class="w"></span>
<span class="w"> </span><span class="n">invoke_my_func</span><span class="w"> </span><span class="p">(</span><span class="n">thread1_main_context</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="s">&quot;some data which needs passing between threads&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="mi">123456</span><span class="p">,</span><span class="w"> </span><span class="n">some_object</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Continue doing other work. */</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>This invocation is uni-directional: it calls <code class="docutils literal notranslate"><span class="pre">my_func()</span></code> in <code class="docutils literal notranslate"><span class="pre">thread1</span></code>, but
theres no way to return a value to the main thread. To do that, the same
principle needs to be used again, invoking a callback function in the main
thread. Its a straightforward extension which isnt covered here.</p>
<p>To maintain thread safety, data which is potentially accessed by multiple
threads must make those accesses mutually exclusive using a mutex. Data
potentially accessed by multiple threads: <code class="docutils literal notranslate"><span class="pre">thread1_main_context</span></code>, passed in
the fork call to <code class="docutils literal notranslate"><span class="pre">thread1_main</span></code>; and <code class="docutils literal notranslate"><span class="pre">some_object</span></code>, a reference to which is
passed in the data closure. Critically, GLib guarantees that <code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> is
thread safe, so sharing <code class="docutils literal notranslate"><span class="pre">thread1_main_context</span></code> between threads is safe. The
example assumes that other code accessing <code class="docutils literal notranslate"><span class="pre">some_object</span></code> is thread safe.</p>
<p>Note that <code class="docutils literal notranslate"><span class="pre">some_string</span></code> and <code class="docutils literal notranslate"><span class="pre">some_int</span></code> cannot be accessed from both threads,
because copies of them are passed to <code class="docutils literal notranslate"><span class="pre">thread1</span></code>, rather than the originals.
This is a standard technique for making cross-thread calls thread safe without
requiring locking. It also avoids the problem of synchronizing freeing
<code class="docutils literal notranslate"><span class="pre">some_string</span></code>.</p>
<p>Similarly, a reference to <code class="docutils literal notranslate"><span class="pre">some_object</span></code> is transferred to <code class="docutils literal notranslate"><span class="pre">thread1</span></code>, which
works around the issue of synchronizing destruction of the object.</p>
<p><code class="docutils literal notranslate"><span class="pre">g_idle_source_new()</span></code> is used rather than the simpler <code class="docutils literal notranslate"><span class="pre">g_idle_add()</span></code> so the
<code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> to attach to can be specified.</p>
</section>
<section id="convenience-method-g-main-context-invoke-full">
<h2>Convenience Method: g_main_context_invoke_full()<a class="headerlink" href="#convenience-method-g-main-context-invoke-full" title="Permalink to this headline">#</a></h2>
<p>This is simplified greatly by the convenience method,
<code class="docutils literal notranslate"><span class="pre">g_main_context_invoke_full()</span></code>. It invokes a callback so that the specified
<code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> is owned during the invocation. Owning a main context is almost
always equivalent to running it, and hence the function is invoked in the thread
for which the specified context is the thread-default.</p>
<p><code class="docutils literal notranslate"><span class="pre">g_main_context_invoke()</span></code> can be used instead if the user data does not need
to be freed by a <code class="docutils literal notranslate"><span class="pre">GDestroyNotify</span></code> callback after the invocation returns.</p>
<p>Modifying the earlier example, the <code class="docutils literal notranslate"><span class="pre">invoke_my_func()</span></code> function can be replaced
by the following:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">invoke_my_func</span><span class="w"> </span><span class="p">(</span><span class="n">GMainContext</span><span class="w"> </span><span class="o">*</span><span class="n">thread1_main_context</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">gchar</span><span class="w"> </span><span class="o">*</span><span class="n">some_string</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">guint</span><span class="w"> </span><span class="n">some_int</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">GObject</span><span class="w"> </span><span class="o">*</span><span class="n">some_object</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">MyFuncData</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Create a data closure to pass all the desired variables</span>
<span class="cm"> * between threads. */</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_new0</span><span class="w"> </span><span class="p">(</span><span class="n">MyFuncData</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_string</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_strdup</span><span class="w"> </span><span class="p">(</span><span class="n">some_string</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_int</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">some_int</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_object</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_object_ref</span><span class="w"> </span><span class="p">(</span><span class="n">some_object</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Invoke the function. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_context_invoke_full</span><span class="w"> </span><span class="p">(</span><span class="n">thread1_main_context</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">G_PRIORITY_DEFAULT</span><span class="p">,</span><span class="w"> </span><span class="n">my_func_idle</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="n">GDestroyNotify</span><span class="p">)</span><span class="w"> </span><span class="n">my_func_data_free</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>Consider what happens if <code class="docutils literal notranslate"><span class="pre">invoke_my_func()</span></code> were called from <code class="docutils literal notranslate"><span class="pre">thread1</span></code>,
rather than from the main thread. With the original implementation, the idle
source would be added to <code class="docutils literal notranslate"><span class="pre">thread1</span></code>s context and dispatched on the contexts
next iteration (assuming no pending dispatches with higher priorities). With the
improved implementation, <code class="docutils literal notranslate"><span class="pre">g_main_context_invoke_full()</span></code> will notice that the
specified context is already owned by the thread (or ownership can be acquired
by it), and will call <code class="docutils literal notranslate"><span class="pre">my_func_idle()</span></code> directly, rather than attaching a
source to the context and delaying the invocation to the next context iteration.</p>
<p>This subtle behavior difference doesnt matter in most cases, but is worth
bearing in mind since it can affect blocking behavior (<code class="docutils literal notranslate"><span class="pre">invoke_my_func()</span></code>
would go from taking negligible time, to taking the same amount of time as
<code class="docutils literal notranslate"><span class="pre">my_func()</span></code> before returning).</p>
</section>
<section id="checking-threading">
<h2>Checking Threading<a class="headerlink" href="#checking-threading" title="Permalink to this headline">#</a></h2>
<p>It is useful to document which thread each function should be called in, in the form of an assertion:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">g_assert</span> <span class="p">(</span><span class="n">g_main_context_is_owner</span> <span class="p">(</span><span class="n">expected_main_context</span><span class="p">));</span>
</pre></div>
</div>
<p>If thats put at the top of each function, any assertion failure will highlight
a case where a function has been called from the wrong thread. It is much easier
to write these assertions when initially developing code, rather than debugging
race conditions which can easily result from a function being called in the
wrong thread.</p>
<p>This technique can also be applied to signal emissions and callbacks, improving
type safety as well as asserting the right context is used. Note that signal
emission via <code class="docutils literal notranslate"><span class="pre">g_signal_emit()</span></code> is synchronous, and doesnt involve a main
context at all.</p>
<p>For example, instead of using the following when emitting a signal:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">guint</span><span class="w"> </span><span class="n">param1</span><span class="p">;</span><span class="w"> </span><span class="cm">/* arbitrary example parameters */</span><span class="w"></span>
<span class="n">gchar</span><span class="w"> </span><span class="o">*</span><span class="n">param2</span><span class="p">;</span><span class="w"></span>
<span class="n">guint</span><span class="w"> </span><span class="n">retval</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="n">g_signal_emit_by_name</span><span class="w"> </span><span class="p">(</span><span class="n">my_object</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="s">&quot;some-signal&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">param1</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">param2</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="o">&amp;</span><span class="n">retval</span><span class="p">);</span><span class="w"></span>
</pre></div>
</div>
<p>The following can be used:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="n">guint</span><span class="w"></span>
<span class="nf">emit_some_signal</span><span class="w"> </span><span class="p">(</span><span class="n">GObject</span><span class="w"> </span><span class="o">*</span><span class="n">my_object</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">guint</span><span class="w"> </span><span class="n">param1</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">gchar</span><span class="w"> </span><span class="o">*</span><span class="n">param2</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">guint</span><span class="w"> </span><span class="n">retval</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">g_assert</span><span class="w"> </span><span class="p">(</span><span class="n">g_main_context_is_owner</span><span class="w"> </span><span class="p">(</span><span class="n">expected_main_context</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="n">g_signal_emit_by_name</span><span class="w"> </span><span class="p">(</span><span class="n">my_object</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;some-signal&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">param1</span><span class="p">,</span><span class="w"> </span><span class="n">param2</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">retval</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">retval</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
</section>
<section id="gtask">
<h2>GTask<a class="headerlink" href="#gtask" title="Permalink to this headline">#</a></h2>
<p><code class="docutils literal notranslate"><span class="pre">GTask</span></code> provides a slightly different approach to invoking functions in other
threads, which is more suited to the case where a function should be executed in
some background thread, but not a specific one.</p>
<p><code class="docutils literal notranslate"><span class="pre">GTask</span></code> takes a data closure and a function to execute, and provides ways to
return the result from this function. It handles everything necessary to run
that function in an arbitrary thread belonging to some thread pool internal to
GLib.</p>
<p>By combining <code class="docutils literal notranslate"><span class="pre">g_main_context_invoke_full()</span></code> and <code class="docutils literal notranslate"><span class="pre">GTask</span></code>, it is possible to
run a task in a specific context and effortlessly return its result to the
current context:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cm">/* This will be invoked in thread1. */</span><span class="w"></span>
<span class="k">static</span><span class="w"> </span><span class="n">gboolean</span><span class="w"></span>
<span class="nf">my_func_idle</span><span class="w"> </span><span class="p">(</span><span class="n">gpointer</span><span class="w"> </span><span class="n">user_data</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">GTask</span><span class="w"> </span><span class="o">*</span><span class="n">task</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">G_TASK</span><span class="w"> </span><span class="p">(</span><span class="n">user_data</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">MyFuncData</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">gboolean</span><span class="w"> </span><span class="n">retval</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Call my_func() and propagate its returned boolean to</span>
<span class="cm"> * the main thread. */</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_task_get_task_data</span><span class="w"> </span><span class="p">(</span><span class="n">task</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">retval</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_func</span><span class="w"> </span><span class="p">(</span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_string</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_int</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_object</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_task_return_boolean</span><span class="w"> </span><span class="p">(</span><span class="n">task</span><span class="p">,</span><span class="w"> </span><span class="n">retval</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">G_SOURCE_REMOVE</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="cm">/* Whichever thread this is invoked in, the @callback will be</span>
<span class="cm"> * invoked in, once my_func() has finished and returned a result. */</span><span class="w"></span>
<span class="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">invoke_my_func_with_result</span><span class="w"> </span><span class="p">(</span><span class="n">GMainContext</span><span class="w"> </span><span class="o">*</span><span class="n">thread1_main_context</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">gchar</span><span class="w"> </span><span class="o">*</span><span class="n">some_string</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">guint</span><span class="w"> </span><span class="n">some_int</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">GObject</span><span class="w"> </span><span class="o">*</span><span class="n">some_object</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">GAsyncReadyCallback</span><span class="w"> </span><span class="n">callback</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">gpointer</span><span class="w"> </span><span class="n">user_data</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">MyFuncData</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Create a data closure to pass all the desired variables</span>
<span class="cm"> * between threads. */</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_new0</span><span class="w"> </span><span class="p">(</span><span class="n">MyFuncData</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_string</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_strdup</span><span class="w"> </span><span class="p">(</span><span class="n">some_string</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_int</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">some_int</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="o">-&gt;</span><span class="n">some_object</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_object_ref</span><span class="w"> </span><span class="p">(</span><span class="n">some_object</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Create a GTask to handle returning the result to the current</span>
<span class="cm"> * thread-default main context. */</span><span class="w"></span>
<span class="w"> </span><span class="n">task</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_task_new</span><span class="w"> </span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">callback</span><span class="p">,</span><span class="w"> </span><span class="n">user_data</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_task_set_task_data</span><span class="w"> </span><span class="p">(</span><span class="n">task</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="n">GDestroyNotify</span><span class="p">)</span><span class="w"> </span><span class="n">my_func_data_free</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Invoke the function. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_main_context_invoke_full</span><span class="w"> </span><span class="p">(</span><span class="n">thread1_main_context</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">G_PRIORITY_DEFAULT</span><span class="p">,</span><span class="w"> </span><span class="n">my_func_idle</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">task</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="n">GDestroyNotify</span><span class="p">)</span><span class="w"> </span><span class="n">g_object_unref</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
</section>
</section>
</article>
<footer>
<div class="related-pages">
<a class="next-page" href="lists.html">
<div class="page-info">
<div class="context">
<span>Next</span>
</div>
<div class="title">Using GLib Lists</div>
</div>
<svg><use href="#svg-arrow-right"></use></svg>
</a>
<a class="prev-page" href="pre-and-post-conditions.html">
<svg><use href="#svg-arrow-right"></use></svg>
<div class="page-info">
<div class="context">
<span>Previous</span>
</div>
<div class="title">Pre- and Post-Conditions</div>
</div>
</a>
</div>
</footer>
</div>
<aside class="toc-drawer">
<div class="toc-sticky toc-scroll">
<div class="toc-title-container">
<span class="toc-title">
Contents
</span>
</div>
<div class="toc-tree-container">
<div class="toc-tree">
<ul>
<li><a class="reference internal" href="#">Main Contexts</a><ul>
<li><a class="reference internal" href="#summary">Summary</a></li>
<li><a class="reference internal" href="#what-is-gmaincontext">What is GMainContext?</a></li>
<li><a class="reference internal" href="#what-is-gmainloop">What is GMainLoop?</a></li>
<li><a class="reference internal" href="#default-contexts">Default Contexts</a></li>
<li><a class="reference internal" href="#implicit-use-of-the-global-default-main-context">Implicit Use of the Global-Default Main Context</a></li>
<li><a class="reference internal" href="#using-gmaincontext-in-a-library">Using GMainContext in a Library</a></li>
<li><a class="reference internal" href="#ensuring-functions-are-called-in-the-right-context">Ensuring Functions are Called in the Right Context</a></li>
<li><a class="reference internal" href="#principles-of-invocation">Principles of Invocation</a></li>
<li><a class="reference internal" href="#convenience-method-g-main-context-invoke-full">Convenience Method: g_main_context_invoke_full()</a></li>
<li><a class="reference internal" href="#checking-threading">Checking Threading</a></li>
<li><a class="reference internal" href="#gtask">GTask</a></li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</aside>
</main>
</div><script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/scripts/furo.js"></script>
</body>
</html>