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

1307 lines
163 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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="Drag and Drop" href="drag-and-drop.html" /><link rel="prev" title="Threading" href="threading.html" />
<meta name="generator" content="sphinx-4.3.0, furo 2022.06.21"/>
<title>Asynchronous Programming - 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"><a class="reference internal" href="main-contexts.html">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 current current-page"><a class="current reference internal" href="#">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="asynchronous-programming">
<h1>Asynchronous Programming<a class="headerlink" href="#asynchronous-programming" 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 asynchronous calls in preference to synchronous calls or explicit use of
threads</p></li>
<li><p>Learn and follow the GLib pattern for declaring asynchronous APIs</p></li>
<li><p>Place callbacks from asynchronous functions in order down the file, so control
flow is easy to follow</p></li>
<li><p>Use the presence of a <code class="docutils literal notranslate"><span class="pre">GTask</span></code> or <code class="docutils literal notranslate"><span class="pre">GCancellable</span></code> to indicate whether an
operation is ongoing</p></li>
<li><p>If running operations in parallel, track how many operations are yet to start,
and how many are yet to finish — the overall operation is complete once both
counts are zero</p></li>
<li><p>Separate state for operations into task data structures for <code class="docutils literal notranslate"><span class="pre">GTask</span></code>,
allowing operations to be reused more easily without needing changes to
global state handling</p></li>
<li><p>Consider how asynchronous methods on an object instance interact with
finalization of that instance</p></li>
</ul>
</section>
<section id="concepts">
<h2>Concepts<a class="headerlink" href="#concepts" title="Permalink to this headline">#</a></h2>
<p>GLib supports <em>asynchronous programming</em>, where long-running operations can be
started, run in the background, and a callback invoked when they are finished
and their results are available. This is in direct contrast to synchronous
long-running operations, which are a single function call which blocks program
control flow until complete.</p>
<p>As discussed in the <a class="reference internal" href="main-contexts.html"><span class="doc">Main Contexts</span></a> and in the
<a class="reference internal" href="threading.html"><span class="doc">Threading</span></a> tutorials, asynchronous operations
should be favoured over synchronous ones and over explicit use of threading.
They do not block the main context like sychronous operations do; and are
easier to use correctly than threads. They often also have a lower performance
penalty than spawning a thread and sending work to it.</p>
</section>
<section id="api-patterns">
<h2>API patterns<a class="headerlink" href="#api-patterns" title="Permalink to this headline">#</a></h2>
<p>Asynchronous calls follow a standard pattern in GLib code. For an operation
named <code class="docutils literal notranslate"><span class="pre">load_data</span></code> on the <code class="docutils literal notranslate"><span class="pre">File</span></code> class in the <code class="docutils literal notranslate"><span class="pre">Foo</span></code> namespace, there will
be:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"></span>
<span class="nf">foo_file_load_data_async</span><span class="w"> </span><span class="p">(</span><span class="n">FooFile</span><span class="w"> </span><span class="o">*</span><span class="n">self</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="c1">// ...,</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="n">gboolean</span><span class="w"></span>
<span class="nf">foo_file_load_data_finish</span><span class="w"> </span><span class="p">(</span><span class="n">FooFile</span><span class="w"> </span><span class="o">*</span><span class="n">self</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="c1">// ...,</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="p">);</span><span class="w"></span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre"></span></code> parameters to <code class="docutils literal notranslate"><span class="pre">foo_file_load_data_async()</span></code> are those specific to the
operation—in this case, perhaps the size of a buffer to load into. Similarly for
<code class="docutils literal notranslate"><span class="pre">foo_file_load_data_finish()</span></code> they are the operation-specific return
values—perhaps a location to return a content type string in this case.</p>
<p>When <code class="docutils literal notranslate"><span class="pre">foo_file_load_data_async()</span></code> is called, it schedules the load operation
in the background (as a new file descriptor on the <code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> or as a
worker thread, for example), then returns without blocking.</p>
<p>When the operation is complete, the callback is executed in the same
<code class="docutils literal notranslate"><span class="pre">GMainContext</span></code> as the original asynchronous call. The callback is invoked
exactly once, whether the operation succeeded or failed.</p>
<p>From the callback, <code class="docutils literal notranslate"><span class="pre">foo_file_load_data_finish()</span></code> may be called by the users
code to retrieve return values and error details, passing the <code class="docutils literal notranslate"><span class="pre">GAsyncResult</span></code>
instance which was passed to the callback.</p>
</section>
<section id="operation-lifetimes">
<h2>Operation Lifetimes<a class="headerlink" href="#operation-lifetimes" title="Permalink to this headline">#</a></h2>
<p>When writing asynchronous operations, it is common to write them as methods of a
class. In this case, it is important to define how ongoing operations on a class
instance interact with finalization of that instance. There are two approaches:</p>
<dl class="simple">
<dt><strong>Strong</strong></dt><dd><p>The ongoing operation keeps a reference to the class instance, forcing it to
remain alive for the duration of the operation. The class should provide some
kind of close or cancel method which can be used by other classes to force
cancellation of the operation and allow that instance to be finalized.</p>
</dd>
<dt><strong>Weak</strong></dt><dd><p>The ongoing operation does <em>not</em> keep a reference to the class instance, and
the class cancels the operation (using <code class="docutils literal notranslate"><span class="pre">g_cancellable_cancel()</span></code>) in its
dispose function.</p>
</dd>
</dl>
<p>Which approach is used depends on the class design. A class which wraps a
particular operation (perhaps a <code class="docutils literal notranslate"><span class="pre">MyFileTransfer</span></code> class, for example) might
want to use the <em>weak</em> approach. A class which manages multiple network
connections and asynchronous operations on them may use the <em>strong</em> approach
instead. Due to incoming network connections, for example, it might not be in
complete control of the scheduling of its asynchronous calls, so the weak
approach would not be appropriate—any code dropping a reference to the object
could not be sure it was not accidentally killing a new network connection.</p>
</section>
<section id="using-asynchronous-functions">
<h2>Using asynchronous functions<a class="headerlink" href="#using-asynchronous-functions" title="Permalink to this headline">#</a></h2>
<p>It is often the case that multiple asynchronous calls need to be used to
complete an operation. For example, opening a file for reading, then performing
a couple of reads, and then closing the file. Or opening several network sockets
in parallel and waiting until they are all open before continuing with other
work. Some examples of these situations are given below.</p>
<section id="single-operation">
<h3>Single operation<a class="headerlink" href="#single-operation" title="Permalink to this headline">#</a></h3>
<p>A single asynchronous call requires two functions: one to start the operation,
and one to complete it. In C, the demanding part of performing an asynchronous
call is correctly storing state between these two functions, and handling
changes to that state in the time between those two functions being called. For
example, cancellation of an ongoing asynchronous call is a state change, and if
not implemented carefully, any UI updates (for example) made when cancelling an
operation will be undone by updates in the operations callback.</p>
<p>The example below demonstrates copying a file from one location in the file
system to another. The key principles demonstrated here are:</p>
<ul class="simple">
<li><p>Placing the <code class="docutils literal notranslate"><span class="pre">copy_button_clicked_cb()</span></code> (start) and <code class="docutils literal notranslate"><span class="pre">copy_finish_cb()</span></code>
(finish) functions in order by using a forward declaration for
<code class="docutils literal notranslate"><span class="pre">copy_finish_cb()</span></code>. This means the control flow continues linearly down the
file, rather than getting to the bottom of <code class="docutils literal notranslate"><span class="pre">copy_button_clicked_cb()</span></code> and
resuming in <code class="docutils literal notranslate"><span class="pre">copy_finish_cb()</span></code> somewhere else in the file.</p></li>
<li><p>Using a <code class="docutils literal notranslate"><span class="pre">GCancellable</span></code> to allow cancelling the operation after it has
started. The code in <code class="docutils literal notranslate"><span class="pre">cancel_button_clicked_cb()</span></code> is very simple: as the
<code class="docutils literal notranslate"><span class="pre">copy_finish_cb()</span></code> callback is guaranteed to be invoked when the operation
completes (even when completing early due to cancellation), all the UI and
state updates for cancellation can be handled there, rather than in
<code class="docutils literal notranslate"><span class="pre">cancel_button_clicked_cb()</span></code>.</p></li>
<li><p>An operation is ongoing exactly while <code class="docutils literal notranslate"><span class="pre">MyObjectPrivate.copy_cancellable</span></code> is
not <code class="docutils literal notranslate"><span class="pre">NULL</span></code>, making it easy to track running operations. Note that this
means only one file copy operation can be started via
<code class="docutils literal notranslate"><span class="pre">copy_button_clicked_cb()</span></code> at a time. One <code class="docutils literal notranslate"><span class="pre">GCancellable</span></code> cannot easily be
used for multiple operations like this.</p></li>
</ul>
<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">copy_finish_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="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">copy_button_clicked_cb</span><span class="w"> </span><span class="p">(</span><span class="n">GtkButton</span><span class="w"> </span><span class="o">*</span><span class="n">button</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">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GFile</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="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">destination</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="cm">/* owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">MY_OBJECT</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="cm">/* Operation already in progress? */</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">priv</span><span class="o">-&gt;</span><span class="n">copy_cancellable</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_debug</span><span class="w"> </span><span class="p">(</span><span class="s">&quot;Copy already in progress.&quot;</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">return</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">/* Build source and destination file paths. */</span><span class="w"></span>
<span class="w"> </span><span class="n">source</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_file_new_for_path</span><span class="w"> </span><span class="p">(</span><span class="cm">/* some path generated from UI */</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">destination</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_file_new_for_path</span><span class="w"> </span><span class="p">(</span><span class="cm">/* some other path generated from UI */</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Set up a cancellable. */</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">copy_cancellable</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_cancellable_new</span><span class="w"> </span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">g_file_copy_async</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">destination</span><span class="p">,</span><span class="w"> </span><span class="n">G_FILE_COPY_NONE</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">priv</span><span class="o">-&gt;</span><span class="n">copy_cancellable</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">copy_finish_cb</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_object_unref</span><span class="w"> </span><span class="p">(</span><span class="n">destination</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">source</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Update UI to show copy is in progress. */</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">copy_finish_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">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GFile</span><span class="w"> </span><span class="o">*</span><span class="n">source</span><span class="p">;</span><span class="w"> </span><span class="cm">/* unowned */</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">source</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">G_FILE</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">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">MY_OBJECT</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="cm">/* Handle completion of the operation. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_file_copy_finish</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">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="w"> </span><span class="o">&amp;&amp;</span><span class="w"></span>
<span class="w"> </span><span class="o">!</span><span class="n">g_error_matches</span><span class="w"> </span><span class="p">(</span><span class="n">error</span><span class="p">,</span><span class="w"> </span><span class="n">G_IO_ERROR</span><span class="p">,</span><span class="w"> </span><span class="n">G_IO_ERROR_CANCELLED</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">/* Should update the UI to signal failure.</span>
<span class="cm"> * Ignore failure due to cancellation. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_warning</span><span class="w"> </span><span class="p">(</span><span class="s">&quot;Failed to copy file: %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="p">}</span><span class="w"></span>
<span class="w"> </span><span class="n">g_clear_error</span><span class="w"> </span><span class="p">(</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="cm">/* Clear the cancellable to signify the operation has finished. */</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">priv</span><span class="o">-&gt;</span><span class="n">copy_cancellable</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Update UI to show copy as complete. */</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">cancel_button_clicked_cb</span><span class="w"> </span><span class="p">(</span><span class="n">GtkButton</span><span class="w"> </span><span class="o">*</span><span class="n">button</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">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GFile</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="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">destination</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="cm">/* owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">MY_OBJECT</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="cm">/* Operation in progress? No-op if @copy_cancellable is %NULL. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_cancellable_cancel</span><span class="w"> </span><span class="p">(</span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">copy_cancellable</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_object_dispose</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">obj</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">MY_OBJECT</span><span class="w"> </span><span class="p">(</span><span class="n">obj</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Cancel any ongoing copy operation.</span>
<span class="cm"> *</span>
<span class="cm"> * This ensures that if #MyObject is disposed part-way through a copy, the</span>
<span class="cm"> * callback doesnt get invoked with an invalid #MyObject pointer. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_cancellable_cancel</span><span class="w"> </span><span class="p">(</span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">copy_cancellable</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Do other dispose calls here. */</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Chain up. */</span><span class="w"></span>
<span class="w"> </span><span class="n">G_OBJECT_CLASS</span><span class="w"> </span><span class="p">(</span><span class="n">my_object_parent_class</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">dispose</span><span class="w"> </span><span class="p">(</span><span class="n">obj</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>For comparison, here is the same code implemented using the synchronous version
of <code class="docutils literal notranslate"><span class="pre">g_file_copy()</span></code>. Note how the order of statements is almost identical. The
UI is blocked from updating and receiving user input, which also means that
cancellation cannot be supported. This is the main reason why this code should
not be used in practice:</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">copy_button_clicked_cb</span><span class="w"> </span><span class="p">(</span><span class="n">GtkButton</span><span class="w"> </span><span class="o">*</span><span class="n">button</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">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GFile</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="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">destination</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="cm">/* owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">MY_OBJECT</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="cm">/* Build source and destination file paths. */</span><span class="w"></span>
<span class="w"> </span><span class="n">source</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_file_new_for_path</span><span class="w"> </span><span class="p">(</span><span class="cm">/* some path generated from UI */</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">destination</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_file_new_for_path</span><span class="w"> </span><span class="p">(</span><span class="cm">/* some other path generated from UI */</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_file_copy</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">destination</span><span class="p">,</span><span class="w"> </span><span class="n">G_FILE_COPY_NONE</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nb">NULL</span><span class="w"> </span><span class="cm">/* cancellable */</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="o">&amp;</span><span class="n">error</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">destination</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">source</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Handle completion of the operation. */</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="cm">/* Should update the UI to signal failure.</span>
<span class="cm"> * Ignore failure due to cancellation. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_warning</span><span class="w"> </span><span class="p">(</span><span class="s">&quot;Failed to copy file: %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="p">}</span><span class="w"></span>
<span class="w"> </span><span class="n">g_clear_error</span><span class="w"> </span><span class="p">(</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="cm">/* Update UI to show copy as complete. */</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
</section>
<section id="operations-in-series">
<h3>Operations in series<a class="headerlink" href="#operations-in-series" title="Permalink to this headline">#</a></h3>
<p>A common situation is to run multiple asynchronous operations in series, when
each operation depends on the previous one completing.</p>
<p>In this example, the application reads a socket address from a file, opens a
connection to that address, reads a message, and then finishes.</p>
<p>Key points in this example are:</p>
<ul class="simple">
<li><p>Each callback is numbered consistently, and they are all placed in order in
the file so the code follows sequentially.</p></li>
<li><p>As in the single-call example, a single <code class="docutils literal notranslate"><span class="pre">GCancellable</span></code> indicates that the
series of operations is ongoing. Cancelling it aborts the entire sequence.</p></li>
<li><p>As in the single-call example, the pending operation is cancelled if the
owning <code class="docutils literal notranslate"><span class="pre">MyObject</span></code> instance is disposed, to prevent callbacks being called
later with an invalid MyObject pointer.</p></li>
</ul>
<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">connect_to_server_cb1</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="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">connect_to_server_cb2</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="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">connect_to_server_cb3</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="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">connect_to_server</span><span class="w"> </span><span class="p">(</span><span class="n">MyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GFile</span><span class="w"> </span><span class="o">*</span><span class="n">address_file</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="cm">/* owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">self</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">priv</span><span class="o">-&gt;</span><span class="n">connect_cancellable</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="cm">/* Already connecting. */</span><span class="w"></span>
<span class="w"> </span><span class="k">return</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">/* Set up a cancellable. */</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">connect_cancellable</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_cancellable_new</span><span class="w"> </span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Read the socket address. */</span><span class="w"></span>
<span class="w"> </span><span class="n">address_file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">build_address_file</span><span class="w"> </span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">g_file_load_contents_async</span><span class="w"> </span><span class="p">(</span><span class="n">address_file</span><span class="p">,</span><span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">connect_cancellable</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">connect_to_server_cb1</span><span class="p">,</span><span class="w"> </span><span class="n">self</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">address_file</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">connect_to_server_cb1</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">MyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GFile</span><span class="w"> </span><span class="o">*</span><span class="n">address_file</span><span class="p">;</span><span class="w"> </span><span class="cm">/* unowned */</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">address</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="cm">/* owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">gsize</span><span class="w"> </span><span class="n">address_size</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">GInetAddress</span><span class="w"> </span><span class="o">*</span><span class="n">inet_address</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="cm">/* owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">GInetSocketAddress</span><span class="w"> </span><span class="o">*</span><span class="n">inet_socket_address</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="cm">/* owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">guint16</span><span class="w"> </span><span class="n">port</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">123</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GSocketClient</span><span class="w"> </span><span class="o">*</span><span class="n">socket_client</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="cm">/* owned */</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">address_file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">G_FILE</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">self</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MY_OBJECT</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">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Finish loading the address. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_file_load_contents_finish</span><span class="w"> </span><span class="p">(</span><span class="n">address_file</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">address</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="o">&amp;</span><span class="n">address_size</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</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="k">goto</span><span class="w"> </span><span class="n">done</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">/* Parse the address. */</span><span class="w"></span>
<span class="w"> </span><span class="n">inet_address</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_inet_address_new_from_string</span><span class="w"> </span><span class="p">(</span><span class="n">address</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">inet_address</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="cm">/* Error. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_set_error</span><span class="w"> </span><span class="p">(</span><span class="o">&amp;</span><span class="n">error</span><span class="p">,</span><span class="w"> </span><span class="n">G_IO_ERROR</span><span class="p">,</span><span class="w"> </span><span class="n">G_IO_ERROR_INVALID_ARGUMENT</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="s">&quot;Invalid address %s.&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">address</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">goto</span><span class="w"> </span><span class="n">done</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">inet_socket_address</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_inet_socket_address_new</span><span class="w"> </span><span class="p">(</span><span class="n">inet_address</span><span class="p">,</span><span class="w"> </span><span class="n">port</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Connect to the given address. */</span><span class="w"></span>
<span class="w"> </span><span class="n">socket_client</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_socket_client_new</span><span class="w"> </span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">g_socket_client_connect_async</span><span class="w"> </span><span class="p">(</span><span class="n">socket_client</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">G_SOCKET_CONNECTABLE</span><span class="w"> </span><span class="p">(</span><span class="n">inet_socket_address</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">connect_cancellable</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">connect_to_server_cb2</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">self</span><span class="p">);</span><span class="w"></span>
<span class="nl">done</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="cm">/* Stop the operation. */</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">g_error_matches</span><span class="w"> </span><span class="p">(</span><span class="n">error</span><span class="p">,</span><span class="w"> </span><span class="n">G_IO_ERROR</span><span class="p">,</span><span class="w"> </span><span class="n">G_IO_ERROR_CANCELLED</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_warning</span><span class="w"> </span><span class="p">(</span><span class="s">&quot;Failed to load server address: %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="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">priv</span><span class="o">-&gt;</span><span class="n">connect_cancellable</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="n">g_free</span><span class="w"> </span><span class="p">(</span><span class="n">address</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">inet_address</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">inet_socket_address</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">socket_client</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">connect_to_server_cb2</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">MyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GSocketClient</span><span class="w"> </span><span class="o">*</span><span class="n">socket_client</span><span class="p">;</span><span class="w"> </span><span class="cm">/* unowned */</span><span class="w"></span>
<span class="w"> </span><span class="n">GSocketConnection</span><span class="w"> </span><span class="o">*</span><span class="n">connection</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="cm">/* owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">GInputStream</span><span class="w"> </span><span class="o">*</span><span class="n">input_stream</span><span class="p">;</span><span class="w"> </span><span class="cm">/* unowned */</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">socket_client</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">G_SOCKET_CLIENT</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">self</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MY_OBJECT</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">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Finish connecting to the socket. */</span><span class="w"></span>
<span class="w"> </span><span class="n">connection</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_socket_client_connect_finish</span><span class="w"> </span><span class="p">(</span><span class="n">socket_client</span><span class="p">,</span><span class="w"> </span><span class="n">result</span><span class="p">,</span><span class="w"></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="k">goto</span><span class="w"> </span><span class="n">done</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">/* Store a reference to the connection so it is kept open while we read from</span>
<span class="cm"> * it: #GInputStream does not keep a reference to a #GIOStream which contains</span>
<span class="cm"> * it. */</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">connection</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">connection</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Read a message from the connection. This uses a single buffer stored in</span>
<span class="cm"> * #MyObject, meaning that only one connect_to_server() operation can run at</span>
<span class="cm"> * any time. The buffer could instead be allocated dynamically if this is a</span>
<span class="cm"> * problem. */</span><span class="w"></span>
<span class="w"> </span><span class="n">input_stream</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_io_stream_get_input_stream</span><span class="w"> </span><span class="p">(</span><span class="n">G_IO_STREAM</span><span class="w"> </span><span class="p">(</span><span class="n">connection</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="n">g_input_stream_read_async</span><span class="w"> </span><span class="p">(</span><span class="n">input_stream</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">message_buffer</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="k">sizeof</span><span class="w"> </span><span class="p">(</span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">message_buffer</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">priv</span><span class="o">-&gt;</span><span class="n">connect_cancellable</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">connect_to_server_cb3</span><span class="p">,</span><span class="w"> </span><span class="n">self</span><span class="p">);</span><span class="w"></span>
<span class="nl">done</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="cm">/* Stop the operation. */</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">g_error_matches</span><span class="w"> </span><span class="p">(</span><span class="n">error</span><span class="p">,</span><span class="w"> </span><span class="n">G_IO_ERROR</span><span class="p">,</span><span class="w"> </span><span class="n">G_IO_ERROR_CANCELLED</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_warning</span><span class="w"> </span><span class="p">(</span><span class="s">&quot;Failed to connect to server: %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="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">priv</span><span class="o">-&gt;</span><span class="n">connect_cancellable</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">priv</span><span class="o">-&gt;</span><span class="n">connection</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="n">g_clear_object</span><span class="w"> </span><span class="p">(</span><span class="o">&amp;</span><span class="n">connection</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">connect_to_server_cb3</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">MyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GInputStream</span><span class="w"> </span><span class="o">*</span><span class="n">input_stream</span><span class="p">;</span><span class="w"> </span><span class="cm">/* unowned */</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="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">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">input_stream</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">G_INPUT_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">self</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MY_OBJECT</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">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Finish reading from the socket. */</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_input_stream_read_finish</span><span class="w"> </span><span class="p">(</span><span class="n">input_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="k">goto</span><span class="w"> </span><span class="n">done</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">/* Handle the message. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_assert_cmpint</span><span class="w"> </span><span class="p">(</span><span class="n">len</span><span class="p">,</span><span class="w"> </span><span class="o">&gt;=</span><span class="p">,</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_cmpuint</span><span class="w"> </span><span class="p">((</span><span class="n">gsize</span><span class="p">)</span><span class="w"> </span><span class="n">len</span><span class="p">,</span><span class="w"> </span><span class="o">&lt;=</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="w"> </span><span class="p">(</span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">message_buffer</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="n">handle_received_message</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">,</span><span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">message_buffer</span><span class="p">,</span><span class="w"> </span><span class="n">len</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="k">goto</span><span class="w"> </span><span class="n">done</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="nl">done</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Unconditionally mark the operation as finished.</span>
<span class="cm"> *</span>
<span class="cm"> * The streams should automatically close as this</span>
<span class="cm"> * last reference is dropped. */</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">priv</span><span class="o">-&gt;</span><span class="n">connect_cancellable</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">priv</span><span class="o">-&gt;</span><span class="n">connection</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="cm">/* Warn about the error. */</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">g_error_matches</span><span class="w"> </span><span class="p">(</span><span class="n">error</span><span class="p">,</span><span class="w"> </span><span class="n">G_IO_ERROR</span><span class="p">,</span><span class="w"> </span><span class="n">G_IO_ERROR_CANCELLED</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_warning</span><span class="w"> </span><span class="p">(</span><span class="s">&quot;Failed to read from the server: %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="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="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_object_dispose</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">obj</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">MY_OBJECT</span><span class="w"> </span><span class="p">(</span><span class="n">obj</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Cancel any ongoing connection operations.</span>
<span class="cm"> *</span>
<span class="cm"> * This ensures that if #MyObject is disposed part-way through the</span>
<span class="cm"> * connect_to_server() sequence of operations, the sequence gets cancelled and</span>
<span class="cm"> * doesnt continue with an invalid #MyObject pointer. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_cancellable_cancel</span><span class="w"> </span><span class="p">(</span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">connect_cancellable</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Do other dispose calls here. */</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Chain up. */</span><span class="w"></span>
<span class="w"> </span><span class="n">G_OBJECT_CLASS</span><span class="w"> </span><span class="p">(</span><span class="n">my_object_parent_class</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">dispose</span><span class="w"> </span><span class="p">(</span><span class="n">obj</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
</section>
<section id="operations-in-parallel">
<h3>Operations in parallel<a class="headerlink" href="#operations-in-parallel" title="Permalink to this headline">#</a></h3>
<p>Another common situation is to run multiple asynchronous operations in parallel,
considering the overall operation complete when all its constituents are
complete.</p>
<p>In this example, the application deletes multiple files in parallel.</p>
<p>Key points in this example are:</p>
<ul class="simple">
<li><p>The number of pending asynchronous operations (ones which have started but not
yet finished) is tracked as <code class="docutils literal notranslate"><span class="pre">n_deletions_pending</span></code>. The <code class="docutils literal notranslate"><span class="pre">delete_files_cb()</span></code>
callback only considers the entire operation complete once this reaches zero.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">n_deletions_to_start</span></code> tracks deletion operations being started, in case
<code class="docutils literal notranslate"><span class="pre">g_file_delete_async()</span></code> manages to use a fast path and complete
synchronously (without blocking).</p></li>
<li><p>As in the single-call example, all pending deletions are cancelled if the
owning <code class="docutils literal notranslate"><span class="pre">MyObject</span></code> instance is disposed, to prevent callbacks being called
later with an invalid <code class="docutils literal notranslate"><span class="pre">MyObject</span></code> pointer.</p></li>
</ul>
<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">delete_files_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="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">delete_files</span><span class="w"> </span><span class="p">(</span><span class="n">MyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">GPtrArray</span><span class="cm">/*&lt;owned GFile*&gt;&gt;*/</span><span class="w"> </span><span class="o">*</span><span class="n">files</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GFile</span><span class="w"> </span><span class="o">*</span><span class="n">address_file</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="cm">/* owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Set up a cancellable if no operation is ongoing already. */</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">priv</span><span class="o">-&gt;</span><span class="n">delete_cancellable</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">priv</span><span class="o">-&gt;</span><span class="n">delete_cancellable</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_cancellable_new</span><span class="w"> </span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">n_deletions_pending</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">priv</span><span class="o">-&gt;</span><span class="n">n_deletions_total</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="cm">/* Update internal state, and temporarily set @n_deletions_to_start. This is</span>
<span class="cm"> * used in delete_files_cb() to avoid indicating the overall operation has</span>
<span class="cm"> * completed while deletions are still being started. This can happen if</span>
<span class="cm"> * g_file_delete_async() completes synchronously, for example if theres a</span>
<span class="cm"> * non-blocking fast path for the given file system. */</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">n_deletions_pending</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">files</span><span class="o">-&gt;</span><span class="n">len</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">n_deletions_total</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">files</span><span class="o">-&gt;</span><span class="n">len</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">n_deletions_to_start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">files</span><span class="o">-&gt;</span><span class="n">len</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Update the UI to indicate the files are being deleted. */</span><span class="w"></span>
<span class="w"> </span><span class="n">update_ui_to_show_progress</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">n_deletions_pending</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">n_deletions_total</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Start all the deletion operations in parallel. They share the same</span>
<span class="cm"> * #GCancellable. */</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</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">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">files</span><span class="o">-&gt;</span><span class="n">len</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</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">GFile</span><span class="w"> </span><span class="o">*</span><span class="n">file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">files</span><span class="o">-&gt;</span><span class="n">pdata</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">n_deletions_to_start</span><span class="o">--</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">g_file_delete_async</span><span class="w"> </span><span class="p">(</span><span class="n">file</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="n">priv</span><span class="o">-&gt;</span><span class="n">delete_cancellable</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">delete_files_cb</span><span class="p">,</span><span class="w"> </span><span class="n">self</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="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">delete_files_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">MyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GFile</span><span class="w"> </span><span class="o">*</span><span class="n">file</span><span class="p">;</span><span class="w"> </span><span class="cm">/* unowned */</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">file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">G_FILE</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">self</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MY_OBJECT</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">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Finish deleting the file. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_file_delete_finish</span><span class="w"> </span><span class="p">(</span><span class="n">file</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="w"> </span><span class="o">&amp;&amp;</span><span class="w"></span>
<span class="w"> </span><span class="o">!</span><span class="n">g_error_matches</span><span class="w"> </span><span class="p">(</span><span class="n">error</span><span class="p">,</span><span class="w"> </span><span class="n">G_IO_ERROR</span><span class="p">,</span><span class="w"> </span><span class="n">G_IO_ERROR_CANCELLED</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_warning</span><span class="w"> </span><span class="p">(</span><span class="s">&quot;Error deleting file: %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="p">}</span><span class="w"></span>
<span class="w"> </span><span class="n">g_clear_error</span><span class="w"> </span><span class="p">(</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="cm">/* Update the internal state. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_assert_cmpuint</span><span class="w"> </span><span class="p">(</span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">n_deletions_pending</span><span class="p">,</span><span class="w"> </span><span class="o">&gt;</span><span class="p">,</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">priv</span><span class="o">-&gt;</span><span class="n">n_deletions_pending</span><span class="o">--</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Update the UI to show progress. */</span><span class="w"></span>
<span class="w"> </span><span class="n">update_ui_to_show_progress</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">n_deletions_pending</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">n_deletions_total</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* If all deletions have completed, and no more are being started,</span>
<span class="cm"> * update the UI to show completion. */</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">priv</span><span class="o">-&gt;</span><span class="n">n_deletions_pending</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">n_deletions_to_start</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">update_ui_to_show_completion</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Clear the operation state. */</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">priv</span><span class="o">-&gt;</span><span class="n">delete_cancellable</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">n_deletions_total</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="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_object_dispose</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">obj</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">MY_OBJECT</span><span class="w"> </span><span class="p">(</span><span class="n">obj</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Cancel any ongoing deletion operations.</span>
<span class="cm"> *</span>
<span class="cm"> * This ensures that if #MyObject is disposed part-way through the</span>
<span class="cm"> * delete_files() set of operations, the set gets cancelled and</span>
<span class="cm"> * doesnt continue with an invalid #MyObject pointer. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_cancellable_cancel</span><span class="w"> </span><span class="p">(</span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">delete_cancellable</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Do other dispose calls here. */</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Chain up. */</span><span class="w"></span>
<span class="w"> </span><span class="n">G_OBJECT_CLASS</span><span class="w"> </span><span class="p">(</span><span class="n">my_object_parent_class</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">dispose</span><span class="w"> </span><span class="p">(</span><span class="n">obj</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
</section>
<section id="wrapping-with-gtask">
<h3>Wrapping with GTask<a class="headerlink" href="#wrapping-with-gtask" title="Permalink to this headline">#</a></h3>
<p>Often when an asynchronous operation (or set of operations) becomes more
complex, it needs associated state. This is typically stored in a custom
structure — but defining a new structure to store the standard callback, user
data and cancellable tuple is laborious. <code class="docutils literal notranslate"><span class="pre">GTask</span></code> eases this by providing a
standardized way to wrap all three, plus extra custom task data.</p>
<p>The use of a <code class="docutils literal notranslate"><span class="pre">GTask</span></code> can replace the use of a <code class="docutils literal notranslate"><span class="pre">GCancellable</span></code> for
indicating whether an operation is ongoing.</p>
<p>This example is functionally the same as the operations in series example,
but refactored to use a <code class="docutils literal notranslate"><span class="pre">GTask</span></code> to wrap the sequence of operations.</p>
<p>Key points in this example are:</p>
<ul class="simple">
<li><p>State which was in <code class="docutils literal notranslate"><span class="pre">MyObjectPrivate</span></code> in the series example is now in the
<code class="docutils literal notranslate"><span class="pre">ConnectToServerData</span></code> closure, which is set as the task data of the
<code class="docutils literal notranslate"><span class="pre">GTask</span></code> representing the overall operation. This means its automatically
freed after the operation returns.</p></li>
<li><p>Furthermore, this means that manipulations of <code class="docutils literal notranslate"><span class="pre">MyObjectPrivate</span></code> state are
limited to the start and end of the sequence of operations, so reusing the
task in different situations becomes possible—for example, it is now a lot
easier to support running multiple such tasks in parallel.</p></li>
<li><p>As the <code class="docutils literal notranslate"><span class="pre">GTask</span></code> holds a reference to <code class="docutils literal notranslate"><span class="pre">MyObject</span></code>, it is impossible for the
object to be disposed while the sequence of operations is ongoing, so the
<code class="docutils literal notranslate"><span class="pre">my_object_dispose()</span></code> code has been removed. Instead, a
<code class="docutils literal notranslate"><span class="pre">my_object_close()</span></code> method exists to allow any pending operations can be
cancelled so <code class="docutils literal notranslate"><span class="pre">MyObject</span></code> can be disposed when desired.</p></li>
</ul>
<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">connect_to_server_cb1</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="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">connect_to_server_cb2</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="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"></span>
<span class="nf">connect_to_server_cb3</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="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">GSocketConnection</span><span class="w"> </span><span class="o">*</span><span class="n">connection</span><span class="p">;</span><span class="w"> </span><span class="cm">/* nullable; owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">guint8</span><span class="w"> </span><span class="n">message_buffer</span><span class="p">[</span><span class="mi">128</span><span class="p">];</span><span class="w"></span>
<span class="p">}</span><span class="w"> </span><span class="n">ConnectToServerData</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">connect_to_server_data_free</span><span class="w"> </span><span class="p">(</span><span class="n">ConnectToServerData</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_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">connection</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="kt">void</span><span class="w"></span>
<span class="nf">my_object_connect_to_server_async</span><span class="w"> </span><span class="p">(</span><span class="n">MyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</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">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</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="nb">NULL</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">ConnectToServerData</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="nb">NULL</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">GFile</span><span class="w"> </span><span class="o">*</span><span class="n">address_file</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="cm">/* owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_return_if_fail</span><span class="w"> </span><span class="p">(</span><span class="n">MY_IS_OBJECT</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="n">g_return_if_fail</span><span class="w"> </span><span class="p">(</span><span class="n">cancellable</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">NULL</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">G_IS_CANCELLABLE</span><span class="w"> </span><span class="p">(</span><span class="n">cancellable</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">self</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">priv</span><span class="o">-&gt;</span><span class="n">connect_task</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_task_report_new_error</span><span class="w"> </span><span class="p">(</span><span class="n">self</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="nb">NULL</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">G_IO_ERROR</span><span class="p">,</span><span class="w"> </span><span class="n">G_IO_ERROR_PENDING</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="s">&quot;Already connecting to the server.&quot;</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">return</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">/* Set up a cancellable. */</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">cancellable</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_object_ref</span><span class="w"> </span><span class="p">(</span><span class="n">cancellable</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">else</span><span class="w"></span>
<span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">cancellable</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_cancellable_new</span><span class="w"> </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">/* Set up the task. */</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="n">self</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_check_cancellable</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">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_malloc0</span><span class="w"> </span><span class="p">(</span><span class="k">sizeof</span><span class="w"> </span><span class="p">(</span><span class="n">ConnectToServerData</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">connect_to_server_data_free</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">cancellable</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">connect_task</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">task</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Read the socket address. */</span><span class="w"></span>
<span class="w"> </span><span class="n">address_file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">build_address_file</span><span class="w"> </span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">g_file_load_contents_async</span><span class="w"> </span><span class="p">(</span><span class="n">address_file</span><span class="p">,</span><span class="w"> </span><span class="n">g_task_get_cancellable</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">connect_to_server_cb1</span><span class="p">,</span><span class="w"> </span><span class="n">g_object_ref</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_object_unref</span><span class="w"> </span><span class="p">(</span><span class="n">address_file</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">task</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">connect_to_server_cb1</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">MyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</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="nb">NULL</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">GFile</span><span class="w"> </span><span class="o">*</span><span class="n">address_file</span><span class="p">;</span><span class="w"> </span><span class="cm">/* unowned */</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">address</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="cm">/* owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">gsize</span><span class="w"> </span><span class="n">address_size</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">GInetAddress</span><span class="w"> </span><span class="o">*</span><span class="n">inet_address</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="cm">/* owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">GInetSocketAddress</span><span class="w"> </span><span class="o">*</span><span class="n">inet_socket_address</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="cm">/* owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">guint16</span><span class="w"> </span><span class="n">port</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">123</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">GSocketClient</span><span class="w"> </span><span class="o">*</span><span class="n">socket_client</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="cm">/* owned */</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">address_file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">G_FILE</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">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">self</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_task_get_source_object</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">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Finish loading the address. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_file_load_contents_finish</span><span class="w"> </span><span class="p">(</span><span class="n">address_file</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">address</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="o">&amp;</span><span class="n">address_size</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</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="k">goto</span><span class="w"> </span><span class="n">done</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">/* Parse the address. */</span><span class="w"></span>
<span class="w"> </span><span class="n">inet_address</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_inet_address_new_from_string</span><span class="w"> </span><span class="p">(</span><span class="n">address</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">inet_address</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="cm">/* Error. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_set_error</span><span class="w"> </span><span class="p">(</span><span class="o">&amp;</span><span class="n">error</span><span class="p">,</span><span class="w"> </span><span class="n">G_IO_ERROR</span><span class="p">,</span><span class="w"> </span><span class="n">G_IO_ERROR_INVALID_ARGUMENT</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="s">&quot;Invalid address %s.&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">address</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">goto</span><span class="w"> </span><span class="n">done</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">inet_socket_address</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_inet_socket_address_new</span><span class="w"> </span><span class="p">(</span><span class="n">inet_address</span><span class="p">,</span><span class="w"> </span><span class="n">port</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Connect to the given address. */</span><span class="w"></span>
<span class="w"> </span><span class="n">socket_client</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_socket_client_new</span><span class="w"> </span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">g_socket_client_connect_async</span><span class="w"> </span><span class="p">(</span><span class="n">socket_client</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">G_SOCKET_CONNECTABLE</span><span class="w"> </span><span class="p">(</span><span class="n">inet_socket_address</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="n">g_task_get_cancellable</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">connect_to_server_cb2</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">g_object_ref</span><span class="w"> </span><span class="p">(</span><span class="n">task</span><span class="p">));</span><span class="w"></span>
<span class="nl">done</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="cm">/* Stop the operation and propagate the error. */</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">priv</span><span class="o">-&gt;</span><span class="n">connect_task</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_task_return_error</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">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="n">g_free</span><span class="w"> </span><span class="p">(</span><span class="n">address</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">inet_address</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">inet_socket_address</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">socket_client</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">task</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">connect_to_server_cb2</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">MyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</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="nb">NULL</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">ConnectToServerData</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="p">;</span><span class="w"> </span><span class="cm">/* unowned */</span><span class="w"></span>
<span class="w"> </span><span class="n">GSocketClient</span><span class="w"> </span><span class="o">*</span><span class="n">socket_client</span><span class="p">;</span><span class="w"> </span><span class="cm">/* unowned */</span><span class="w"></span>
<span class="w"> </span><span class="n">GSocketConnection</span><span class="w"> </span><span class="o">*</span><span class="n">connection</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="cm">/* owned */</span><span class="w"></span>
<span class="w"> </span><span class="n">GInputStream</span><span class="w"> </span><span class="o">*</span><span class="n">input_stream</span><span class="p">;</span><span class="w"> </span><span class="cm">/* unowned */</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">socket_client</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">G_SOCKET_CLIENT</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">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">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">self</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_task_get_source_object</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">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Finish connecting to the socket. */</span><span class="w"></span>
<span class="w"> </span><span class="n">connection</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_socket_client_connect_finish</span><span class="w"> </span><span class="p">(</span><span class="n">socket_client</span><span class="p">,</span><span class="w"> </span><span class="n">result</span><span class="p">,</span><span class="w"></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="k">goto</span><span class="w"> </span><span class="n">done</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">/* Store a reference to the connection so it is kept open while we read from</span>
<span class="cm"> * it: #GInputStream does not keep a reference to a #GIOStream which contains</span>
<span class="cm"> * it. */</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="o">-&gt;</span><span class="n">connection</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">connection</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Read a message from the connection. As the buffer is allocated as part of</span>
<span class="cm"> * the per-task @data, multiple tasks can run concurrently. */</span><span class="w"></span>
<span class="w"> </span><span class="n">input_stream</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_io_stream_get_input_stream</span><span class="w"> </span><span class="p">(</span><span class="n">G_IO_STREAM</span><span class="w"> </span><span class="p">(</span><span class="n">connection</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="n">g_input_stream_read_async</span><span class="w"> </span><span class="p">(</span><span class="n">input_stream</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">message_buffer</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="k">sizeof</span><span class="w"> </span><span class="p">(</span><span class="n">data</span><span class="o">-&gt;</span><span class="n">message_buffer</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">g_task_get_cancellable</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">connect_to_server_cb3</span><span class="p">,</span><span class="w"> </span><span class="n">g_object_ref</span><span class="w"> </span><span class="p">(</span><span class="n">task</span><span class="p">));</span><span class="w"></span>
<span class="nl">done</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="cm">/* Stop the operation and propagate the error. */</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">priv</span><span class="o">-&gt;</span><span class="n">connect_task</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_task_return_error</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">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="n">g_clear_object</span><span class="w"> </span><span class="p">(</span><span class="o">&amp;</span><span class="n">connection</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">task</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">connect_to_server_cb3</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">MyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</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="nb">NULL</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">ConnectToServerData</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="p">;</span><span class="w"> </span><span class="cm">/* unowned */</span><span class="w"></span>
<span class="w"> </span><span class="n">GInputStream</span><span class="w"> </span><span class="o">*</span><span class="n">input_stream</span><span class="p">;</span><span class="w"> </span><span class="cm">/* unowned */</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="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">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">input_stream</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">G_INPUT_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">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">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">self</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_task_get_source_object</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">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Finish reading from the socket. */</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_input_stream_read_finish</span><span class="w"> </span><span class="p">(</span><span class="n">input_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="k">goto</span><span class="w"> </span><span class="n">done</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">/* Handle the message. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_assert_cmpint</span><span class="w"> </span><span class="p">(</span><span class="n">len</span><span class="p">,</span><span class="w"> </span><span class="o">&gt;=</span><span class="p">,</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_cmpuint</span><span class="w"> </span><span class="p">((</span><span class="n">gsize</span><span class="p">)</span><span class="w"> </span><span class="n">len</span><span class="p">,</span><span class="w"> </span><span class="o">&lt;=</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="w"> </span><span class="p">(</span><span class="n">data</span><span class="o">-&gt;</span><span class="n">message_buffer</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="n">handle_received_message</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="o">-&gt;</span><span class="n">message_buffer</span><span class="p">,</span><span class="w"> </span><span class="n">len</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="k">goto</span><span class="w"> </span><span class="n">done</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">/* Success! */</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="nl">done</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Unconditionally mark the operation as finished.</span>
<span class="cm"> *</span>
<span class="cm"> * The streams should automatically close as this</span>
<span class="cm"> * last reference is dropped. */</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">priv</span><span class="o">-&gt;</span><span class="n">connect_task</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="cm">/* Stop the operation and propagate the error. */</span><span class="w"></span>
<span class="w"> </span><span class="n">g_task_return_error</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">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="n">g_clear_object</span><span class="w"> </span><span class="p">(</span><span class="o">&amp;</span><span class="n">task</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="kt">void</span><span class="w"></span>
<span class="nf">my_object_connect_to_server_finish</span><span class="w"> </span><span class="p">(</span><span class="n">MyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</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">GError</span><span class="w"> </span><span class="o">**</span><span class="n">error</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_return_if_fail</span><span class="w"> </span><span class="p">(</span><span class="n">MY_IS_OBJECT</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="n">g_return_if_fail</span><span class="w"> </span><span class="p">(</span><span class="n">g_task_is_valid</span><span class="w"> </span><span class="p">(</span><span class="n">result</span><span class="p">,</span><span class="w"> </span><span class="n">self</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="n">g_return_if_fail</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="w"> </span><span class="o">||</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">g_task_propagate_boolean</span><span class="w"> </span><span class="p">(</span><span class="n">G_TASK</span><span class="w"> </span><span class="p">(</span><span class="n">result</span><span class="p">),</span><span class="w"> </span><span class="n">error</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="kt">void</span><span class="w"></span>
<span class="nf">my_object_close</span><span class="w"> </span><span class="p">(</span><span class="n">MyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">MyObjectPrivate</span><span class="w"> </span><span class="o">*</span><span class="n">priv</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">g_return_if_fail</span><span class="w"> </span><span class="p">(</span><span class="n">MY_IS_OBJECT</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="n">priv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">my_object_get_instance_private</span><span class="w"> </span><span class="p">(</span><span class="n">self</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">priv</span><span class="o">-&gt;</span><span class="n">connect_task</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">GCancellable</span><span class="w"> </span><span class="o">*</span><span class="n">cancellable</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_task_get_cancellable</span><span class="w"> </span><span class="p">(</span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">connect_task</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">g_cancellable_cancel</span><span class="w"> </span><span class="p">(</span><span class="n">cancellable</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>
</pre></div>
</div>
</section>
</section>
</section>
</article>
<footer>
<div class="related-pages">
<a class="next-page" href="drag-and-drop.html">
<div class="page-info">
<div class="context">
<span>Next</span>
</div>
<div class="title">Drag and Drop</div>
</div>
<svg><use href="#svg-arrow-right"></use></svg>
</a>
<a class="prev-page" href="threading.html">
<svg><use href="#svg-arrow-right"></use></svg>
<div class="page-info">
<div class="context">
<span>Previous</span>
</div>
<div class="title">Threading</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="#">Asynchronous Programming</a><ul>
<li><a class="reference internal" href="#summary">Summary</a></li>
<li><a class="reference internal" href="#concepts">Concepts</a></li>
<li><a class="reference internal" href="#api-patterns">API patterns</a></li>
<li><a class="reference internal" href="#operation-lifetimes">Operation Lifetimes</a></li>
<li><a class="reference internal" href="#using-asynchronous-functions">Using asynchronous functions</a><ul>
<li><a class="reference internal" href="#single-operation">Single operation</a></li>
<li><a class="reference internal" href="#operations-in-series">Operations in series</a></li>
<li><a class="reference internal" href="#operations-in-parallel">Operations in parallel</a></li>
<li><a class="reference internal" href="#wrapping-with-gtask">Wrapping with GTask</a></li>
</ul>
</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>