95 Commits

Author SHA1 Message Date
julioest
485978d7e0 docs: add preview build workflow README 2026-02-24 03:33:59 -05:00
julioest
07f924fff5 fix: style guide overflow, centering, and add theme toggle 2026-02-24 03:30:02 -05:00
julioest
3b155defff feat: add build-preview script, landing page, and reorganize preview structure 2026-02-24 03:21:44 -05:00
julioest
8a14259558 fix: replace undefined primary-250/750 with semantic surface token 2026-02-24 01:41:43 -05:00
julioest
4b710cbec1 feat: rename colors-blue to colors-secondary to match Figma
- Rename --colors-blue-* to --colors-secondary-* across all source files
- Update style guide section heading and swatches
- Rebuild boostlook-v3.css
2026-02-24 01:17:00 -05:00
julioest
c45dfcc0c1 fix: remove unused color primitives and content indentation
- Remove unused color steps across brand-orange, negative, positive, warning, blue, and primary scales
- Remove legacy code syntax palette (colors-code-colors-*)
- Remove unused atom-one-dark/light variables
- Remove margin-left indentation from code blocks, admonitions, and tables
- Rebuild boostlook-v3.css
2026-02-24 00:40:56 -05:00
julioest
668f975dc3 feat: rename color primitives from neutral to primary, match Figma specs
- Rename --colors-neutral-* to --colors-primary-* across all source files
- Add --colors-primary-650 (#585A64) for body text
- Add --surface-page semantic token (#F7FDFE) for page background
- Update style guide section heading and swatches
- Rebuild boostlook-v3.css
2026-02-24 00:35:27 -05:00
julioest
74afd89596 fix: match body text to Figma specs
- font-variation-settings: wght 400, wdth 95
- line-height: 120%
- letter-spacing: -1%
- color: Text/Secondary
2026-02-23 22:57:21 -05:00
julioest
79e8c06aed fix: use font-variation-settings for weight demos in style guide
Restore font-variation-settings in @font-face and use explicit
wght axis values on style guide elements instead of font-weight.
2026-02-23 22:55:18 -05:00
julioest
66ce50147e fix: remove font-variation-settings that locked weight to 400
The font-variation-settings in @font-face was overriding the
font-weight range, preventing variable font weights from working.
2026-02-23 22:54:16 -05:00
julioest
a2fc113f1e fix: update style guide to use correct variable font files 2026-02-23 22:52:43 -05:00
julioest
e9d2947324 fix: remove symlink before copying CSS in Netlify build 2026-02-23 22:45:03 -05:00
julioest
ad07ed21ce fix: copy CSS into preview dir during Netlify build
The symlink to boostlook-v3.css points outside the publish
directory, so Netlify can't resolve it.
2026-02-23 22:44:30 -05:00
julioest
de87a3e398 fix: add netlify.toml to publish from preview/ directory 2026-02-23 20:27:27 -05:00
julioest
b88e07d446 build: rebuild boostlook-v3.css from updated sources 2026-02-23 20:08:15 -05:00
julioest
0e53f8a619 fix: refine v3 CSS variables, typography, code blocks, and doc styles 2026-02-23 20:00:12 -05:00
julioest
c4f5d7d3be feat: add preview site for Netlify deployment 2026-02-23 20:00:04 -05:00
julioest
8f92b1e120 fix: refine typography
- Scale inline code in headings to 0.85em with font-weight 400
- Reduce inline code in paragraphs from 0.96em to 0.88em
- Match line-height (1.5rem) across p, ul, and ol elements
- Widen condensed text from wdth 80 to 87.5
- Reduce heading margin-top from 2rem to 1.5rem
2026-02-19 18:39:12 -05:00
julioest
9019bd322b fix: remove dead code and commented-out CSS from boostlook.css 2026-02-17 19:09:25 -05:00
julioest
1fda28e1b7 feat: add boostlook-v3.css development build 2026-02-17 19:09:25 -05:00
julioest
ed2cb1636c feat: add modular v3 CSS source and build script 2026-02-17 19:09:25 -05:00
julioest
1f8d2f8a79 fix: remove unused local font files 2026-02-17 19:09:25 -05:00
Julio Estrada
373ad4649e feat: add search input and results dropdown styling (#142)
- Search input with inline SVG icon
  - Responsive dropdown positioning for mobile, tablet, and desktop
  - Mobile layout with full-width search on second row
2026-01-16 02:49:40 -05:00
Julio Estrada
edfeff5eea fix: improve text legibility (#569)
- Fix CSS selector syntax (missing commas in dark theme rules)
- Correct positive-primary color hex code (#f6fafd -> #f0fef7)
- Adjust background colors for light and dark themes
- Remove borders and shadows from code blocks
- Update sidebar margins and borders for better layout
- Refine blockquote styles for consistency
2025-12-28 07:07:37 -05:00
Julio Estrada
f056e064ea refactor: streamline font URLs, remove comments
- Streamline font source URLs in @font-face declarations
- Remove unnecessary comments
2025-12-18 16:31:19 -05:00
Julio Estrada
d264e70b57 fix: enable contextual alternates in code blocks 2025-12-16 14:32:25 -05:00
Julio Estrada
858f832cf5 fix: add cpp-comment class styling support 2025-12-11 18:02:08 -05:00
Julio Estrada
6adfbca7ab fix: disable ligatures in code blocks 2025-12-11 17:55:35 -05:00
Julio Estrada
db04621383 feat: update to Monaspace variable fonts 2025-12-10 21:46:16 -05:00
Julio Estrada
dec44ce10a fix: adjust font feature settings 2025-12-10 19:50:44 -05:00
Julio Estrada
ab2d0fda0a feat: enhance code styling with font feature settings for improved typography 2025-12-10 18:19:57 -05:00
Julio Estrada
8c9f0364d1 refactor: remove Monaspace Radon font references and update to Monaspace Xenon 2025-12-10 16:54:46 -05:00
Julio Estrada
e32c8bda45 feat: update font to Monaspace Xenon Italic 2025-12-10 16:10:38 -05:00
Julio Estrada
76d10265f5 add comment styling with Monaspace Radon font 2025-12-10 01:47:39 -05:00
Julio Estrada
2afbebc0c5 feat: add Monaspace Radon Italic font 2025-12-10 01:25:05 -05:00
Julio Estrada
d0cc6d5e1e refactor: update monospaced font to Monaspace Neon 2025-12-09 18:19:09 -05:00
Julio Estrada
20ddde5333 fix: update workflow dependencies
- Upgrade actions/checkout from v4 to v6
- Upgrade Python from 3.11 to 3.13
2025-11-20 18:40:00 -05:00
Julio Estrada
66401ab4d7 fix: change font-display swap to block
Prevent FOUT by blocking text render until fonts load
2025-11-20 14:31:37 -05:00
Julio Estrada
cdfdff1a43 Prioritize local fonts for antora bundles
Add local font paths first in @font-face src to check for fonts
in antora-bundled projects before remote fallbacks. Required
before boostorg/website-v2-docs#545 can merge.
2025-11-19 23:27:51 -05:00
Julio Estrada
c8ea8e2061 fix foit: swap, fallbacks, metric overrides (#145)
- use font-display: swap to avoid invisible text
- add system fallbacks for body/code stacks
- add size-adjust/ascent/descent/line-gap to reduce cls

refs: issue #145
2025-09-29 16:45:47 -04:00
Julio Estrada
5454b1c038 remove visited link color overrides 2025-09-16 14:34:52 -04:00
Julio Estrada
34fb6a94b3 fix: update font source to noto sans italic 2025-09-13 18:30:00 -04:00
Julio Estrada
b4306e4b94 Fix dark mode background for library readme 2025-07-18 12:39:16 -04:00
Tino
36d2ef80b0 Changed the font-variation-settings value for .boostlook .doc .conum[data-value] to "wght" 350, "wdth" 80 2025-07-07 12:05:53 -04:00
Julio Estrada
6ab075ff7f Add disabled state styles for navigation 2025-07-03 16:02:05 -04:00
Tino
38452398bb Added a background for the tabs
Dark and light theme
https://prnt.sc/rXcjFgvOTX7Y
https://prnt.sc/gT8x9Hto1yeL
2025-07-03 09:08:08 -04:00
Tino
95ac38a2af Added a background for the tabs
Dark and light theme
https://prnt.sc/rXcjFgvOTX7Y
https://prnt.sc/gT8x9Hto1yeL
2025-07-03 09:08:08 -04:00
Tino
a588568d28 Made the callout boxes lighter and removed the borders
Notes
https://prnt.sc/jMmRqNA3smzv
Tips
https://prnt.sc/JOf8-1WyjlsZ
Important
https://prnt.sc/tsyMK-BZuOb-
2025-07-03 09:08:08 -04:00
Tino
db0140e77c Added a 1.3rem spacing above headers https://prnt.sc/wtzXaN00stUT
Added #f9f9f9 for light and #1c1c1c for dark. Also added the margin-top for these blocks to 1.3rem https://prnt.sc/07r8Ha27-jil https://prnt.sc/Qa3zqGYOqIGy

Added more space between paragraphs , from 0.25 rem to 1rem https://prnt.sc/pu54b-EtLXmY

Added boostlook font variation settings “wght” 350 instead of 400
2025-07-03 09:08:08 -04:00
Tino
4071795de1 Removed the previously added numbered list formatting in the code block. Added brackets to match the styles in the tabs next to it. https://prnt.sc/thfGrbTB4qo- 2025-07-02 10:47:49 -04:00
Tino
14c9e079a0 Removed the background of the image in tables and tabs https://prnt.sc/izgdjnKoXPRw
Aligned correctly Note block in table  https://prnt.sc/BBLqUMoFztFI
2025-07-02 10:47:49 -04:00
Tino
99cd5620b7 Fix for <ol> lists 2025-06-26 18:42:55 -04:00
Tino
9c55ac6ddf Added left indents for Note boxes, tables and code blocks. 2025-06-26 18:42:55 -04:00
Tino
47f31fb1bf Removed background color from an image block 2025-06-26 18:42:55 -04:00
Tino
70f75fb9ba Fix conflict 2025-06-26 18:42:55 -04:00
Tino
5d8e2f099e Fix conflict 2025-06-26 18:42:55 -04:00
Tino
c1e9536804 Fix conflict 2025-06-26 18:42:55 -04:00
Tino
af6de4ca0b Added missing padding on code boxes 2025-06-26 18:42:55 -04:00
Tino
b4d7057719 <em> font style fix 2025-06-26 18:42:55 -04:00
Tino
a720b59a65 Added . at the end of the list numbering digits 2025-06-26 18:42:55 -04:00
Tino
eaf1bfdd36 Fix font styles and layout issues in documentation
Updated emphasized text (<em>) to use standard font family with proper italics instead of monospace.

Fixed borders on documentation pages (Beast library example).

Added missing padding to code blocks for better readability.
2025-06-25 18:33:20 -04:00
Tino
a605eee2d3 Left padding space fix 2025-06-25 10:46:18 -04:00
Tino
66d701fed4 Fixed Antora layout 2025-06-25 10:46:18 -04:00
Tino
a8c5b634e1 Removed the top grey area from the layout.
Reduced the upset in the list boulet.

Wrapped all "Note" texts in a colored box for better visibility.

Aligned all the elements in the boxes.
2025-06-25 10:46:18 -04:00
Julio Estrada
757e3c16c9 fix: correct content margin for Antora layout 2025-06-20 20:51:37 -04:00
Tino
e1412c671e Removed the top grey area from the layout.
Reverted numerical values to standard format (removed brackets).

Updated header style to have no background or border.

Wrapped all "Note" texts in a colored box for better visibility.

Standardized styling of tables, boxes, and other components with square corners.

Ensured <h5> tags are no smaller than body text; scaled overall typography as needed.
2025-06-18 16:10:57 +03:00
Julio Estrada
2ea58f2693 style: enhance responsive TOC layout for various screens 2025-06-17 09:34:57 -04:00
Julio Estrada
f8a393d7ed fix: adjust asciidoc layout to use full width 2025-06-03 17:12:13 -04:00
Julio Estrada
1b0f191b58 refactor: comment out TOC toggle functionality 2025-05-30 12:01:06 -04:00
Julio Estrada
9bb732f91b Revert "refactor: always show TOC, remove toggle functionality"
This reverts commit d9059ad133.
2025-05-29 15:31:10 -04:00
Julio Estrada
d9059ad133 refactor: always show TOC, remove toggle functionality 2025-05-29 14:36:30 -04:00
Julio Estrada
4aac76ddd2 style: update border-radius and line-height in CSS 2025-05-20 14:23:41 -04:00
Julio Estrada
ba1af1d32d fix: add overflow-y to scrollbar styling 2025-05-20 13:04:40 -04:00
rbbeeston
527bfdfc95 requested changes and widening 2025-05-14 16:43:05 -07:00
Julio Estrada
8d8e85d6ca refactor: improve CSS consistency and cleanup
- Remove redundant padding for active nav item
- Remove font-weight declarations
- Replace font-weight with font-variation-settings
- Enhance font-variation-settings
2025-04-28 18:45:39 -04:00
Julio Estrada
c597e7372e refactor: standardize font family to Noto Sans 2025-04-25 14:57:27 -04:00
Julio Estrada
3bedf84a63 refactor: update font variation settings for better scaling
Updates font variation settings and stretch properties across Noto Sans fonts: - Changes font-stretch from semi-condensed to 62.5% 100% range - Updates font-variation-settings wdth from 90 to 62.5 - Adds consistent font-stretch ranges to all font declarations - Sets base container font-variation-settings to wght 400, wdth 80
2025-04-24 19:21:51 -04:00
Julio Estrada
d1b966dbd1 fix: update font source formats in boostlook.css 2025-04-23 15:35:47 -04:00
Julio Estrada
f5513867a8 update font settings and add new font files 2025-04-22 16:17:27 -04:00
rbbeeston
61820c5ee7 minor tweaks 2025-04-16 11:18:22 -07:00
wdm-ih
bcb3cb530f qa: add blocks indentation; rework definition list
- add left indentation for: definition list, table, quote block;
- rework styles for definition list block and nested definition list block
2025-04-14 12:30:22 -04:00
Julio Estrada
8eb5871cb2 feat: add Atom One Dark and Light theme colors
style: enhance syntax highlighting for dark/light themes
2025-04-10 18:32:37 -04:00
Julio Estrada
e0ecfc91c5 chore: simplify sync workflow for boostlook.css 2025-04-10 17:17:02 -04:00
Julio Estrada
e130dc047b fix(antora): remove fixed height from doc content 2025-04-10 14:17:04 -04:00
wdm-ih
fe8033808f qa: updated call-out blocks appearance 2025-04-10 13:37:52 -04:00
Julio Estrada
ec37dd0b36 remove boostlook_tino.css file from the project 2025-04-09 15:10:11 -04:00
Julio Estrada
e79effb823 update font sources in boostlook.css to WOFF formats 2025-04-09 15:10:11 -04:00
Julio Estrada
b0a65d53d8 replace boostlook.css styles with boostlook_tino.css stylesq 2025-04-09 15:10:11 -04:00
wdm-ih
f173718329 qa: improves styles for various blocks and element
- minor fix of code block left margin
- replace dot symbol with unicode representation
- add styles to header links without .anchor elem inside
replaced home icon
- reduces navigation buttons gap and removes buttons border
- changes font style and increases spacing between table, code titles
- fixes toc toggle styles and toc container paddings
- add left margin for code blocks, improved syntax highlight
- reduce table cell paddings; fixed border radius for tables
- removed background of inline code elements
- updated in-text link styles
- removed background for inline code links
2025-04-09 12:58:03 -04:00
Julio Estrada
2ee6dc59fa refactor: optimize font sources in boostlook.css
Replace font URLs with WOFF/WOFF2 formats to resolve 404s we got in the v2 project.
2025-04-08 12:41:18 -07:00
wdm-ih
3aaa0db5d6 fix: QA fixes, Antora template update
Fixed issues found during QA.

Resolved issue with the Table of Contents block after the original layout changed.

Replaced the ID for the Antora template from "boost-legacy-docs-wrapper" to "antora-template-wrapper".

Added fallback selectors in case the ID is not provided.

Performed manual QA on charconv, beast, outcome library docs, and contributors docs.

charconv like temlates fix
2025-03-25 13:44:48 -04:00
wdm-ih
a5041ced2d Fix styling issues:
- Removed rounded corner on the left side;
- Fixed visited link hover color in Quickbooks docs;
- Improved styling for Readme docs;
- Aligned first tab text height;
- Applied hover styling to inactive tabs;
- Fixed black text in dark mode tables;
- Fixed black text on hover in dark mode page navigation
2025-03-18 10:58:01 +02:00
wdm-ih
f7148a3dc6 add macos .DS_Store to .gitignore 2025-03-18 10:58:01 +02:00
Julio Estrada
0f18ac59c2 add tino design system 2025-03-15 10:25:05 -04:00
Julio Estrada
473cd45074 gha: enhance CSS sync workflow with branch support
This commit improves the boostlook CSS sync workflow:
- add support for the develop branch
- include boostlook_tino.css in trigger paths
- implement conditional file copying based on branch
- restrict ui-release trigger to push events only
- pass branch name as parameter to downstream workflows
2025-03-14 18:19:53 -04:00
1073 changed files with 465113 additions and 3331 deletions

View File

@@ -2,7 +2,7 @@ name: Sync boostlook.css to website-v2 & website-v2-docs
on:
push:
branches: ["master"]
branches: ["develop"]
paths:
- "boostlook.css"
workflow_dispatch:
@@ -16,10 +16,10 @@ jobs:
if: github.repository == 'boostorg/boostlook'
steps:
- name: Checkout current repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Checkout website-v2 repository
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
repository: boostorg/website-v2
ref: develop
@@ -29,7 +29,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.11"
python-version: "3.13"
- name: Copy boostlook.css to website-v2
run: |

1
.gitignore vendored
View File

@@ -1 +1,2 @@
doc/html
.DS_Store

BIN
MonaspaceNeon-Var.woff2 Normal file

Binary file not shown.

BIN
MonaspaceXenon-Var.woff2 Normal file

Binary file not shown.

1
_ Symbolic link
View File

@@ -0,0 +1 @@
preview/_

5012
boostlook-v3.css Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -3,13 +3,21 @@ Asciidoctor::Extensions.register do
process do |doc, output|
output = output.sub(/(<body[^>]*>)/, '\1<div class="boostlook">')
output = output.sub('</body>', '</div></body>')
output = output.sub(/(<body.*?<div[^>]*id="toc"[^>]*>)/m, '\1<button id="toggle-toc" title="Show Table of Contents" aria-expanded="false" aria-controls="toc">☰</button>')
# Comment out toggle button - TOC should always be visible
# output = output.sub(/(<body.*?<div[^>]*id="toc"[^>]*>)/m, '\1<button id="toggle-toc" title="Show Table of Contents" aria-expanded="false" aria-controls="toc">☰</button>')
output = output.sub(/(<body.*?<div[^>]*id="footer"[^>]*>)/m, '</div>\1')
script_tag = <<~SCRIPT
<script>
(function() {
const html = document.documentElement;
// Always show TOC - no toggle functionality needed
html.classList.add('toc-visible');
html.classList.add('toc-pinned');
html.classList.remove('toc-hidden');
// Comment out toggle functionality since TOC should always be visible
/*
const isPinned = localStorage.getItem('tocPinned') === 'true';
html.classList.add('toc-hidden');
@@ -56,6 +64,7 @@ Asciidoctor::Extensions.register do
updateTocVisibility(isPinned);
});
*/
})();
</script>
SCRIPT

File diff suppressed because it is too large Load Diff

21
build-css.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/sh
# Concatenate CSS modules into boostlook-v3.css
cat \
src/css/00-header.css \
src/css/01-variables.css \
src/css/02-themes.css \
src/css/03-fonts.css \
src/css/04-reset.css \
src/css/05-global-typography.css \
src/css/06-global-links.css \
src/css/07-global-code.css \
src/css/08-global-components.css \
src/css/09-global-tables-images.css \
src/css/10-scrollbars.css \
src/css/11-template-layout.css \
src/css/12-asciidoctor.css \
src/css/13-antora.css \
src/css/14-quickbook.css \
src/css/15-readme.css \
src/css/16-responsive-toc.css \
> boostlook-v3.css

95
build-preview.sh Executable file
View File

@@ -0,0 +1,95 @@
#!/bin/sh
# Build preview site from website-v2-docs and swap in boostlook-v3.css
#
# Usage:
# ./build-preview.sh # build lib docs + site docs, sync into preview/
# ./build-preview.sh --css-only # just rebuild CSS and swap it in
# ./build-preview.sh --serve # just start the local server
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
DOCS_DIR="$SCRIPT_DIR/../website-v2-docs"
BOOST_DIR="$HOME/boost"
PREVIEW_DIR="$SCRIPT_DIR/preview"
BUILD_DIR="$DOCS_DIR/build"
PORT=8000
css_swap() {
echo "Swapping boostlook-v3.css into preview..."
cp "$SCRIPT_DIR/boostlook-v3.css" "$PREVIEW_DIR/_/css/boostlook.css"
}
serve() {
echo "Serving preview at http://localhost:$PORT/"
open "http://localhost:$PORT/"
cd "$PREVIEW_DIR"
python3 -m http.server "$PORT"
}
if [ "$1" = "--serve" ]; then
serve
exit 0
fi
if [ ! -d "$DOCS_DIR" ]; then
echo "Error: website-v2-docs not found at $DOCS_DIR"
exit 1
fi
if [ ! -d "$BOOST_DIR" ]; then
echo "Error: boost superproject not found at $BOOST_DIR"
exit 1
fi
# Rebuild CSS from sources
echo "Building boostlook-v3.css..."
sh "$SCRIPT_DIR/build-css.sh"
if [ "$1" = "--css-only" ]; then
css_swap
echo "Done (CSS only)."
exit 0
fi
# Build library docs
echo "Building library docs..."
cd "$DOCS_DIR"
sh libdoc.sh develop
# Build site docs
echo "Building site docs..."
sh sitedoc.sh develop
# Sync capy library docs into preview/capy/
echo "Syncing capy docs into preview..."
mkdir -p "$PREVIEW_DIR/capy"
rsync -a --delete "$BUILD_DIR/lib/doc/capy/" "$PREVIEW_DIR/capy/"
# Sync UI assets (fonts, JS, images)
echo "Syncing UI assets..."
rsync -a "$BUILD_DIR/lib/doc/_/" "$PREVIEW_DIR/_/"
# Sync site docs
echo "Syncing site docs..."
for dir in user-guide contributor-guide formal-reviews; do
if [ -d "$BUILD_DIR/$dir" ]; then
rsync -a "$BUILD_DIR/$dir/" "$PREVIEW_DIR/$dir/"
fi
done
# Build charconv (asciidoctor + b2)
echo "Building charconv docs..."
cp "$SCRIPT_DIR/boostlook-v3.css" "$BOOST_DIR/tools/boostlook/boostlook.css"
cd "$BOOST_DIR/libs/charconv/doc"
"$BOOST_DIR/b2" html_
mkdir -p "$PREVIEW_DIR/charconv"
cp "$BOOST_DIR/libs/charconv/doc/html/charconv.html" "$PREVIEW_DIR/charconv/index.html"
# Swap in our CSS
css_swap
echo "Done. Preview ready at preview/"
# Start local server
serve

3
netlify.toml Normal file
View File

@@ -0,0 +1,3 @@
[build]
publish = "preview/"
command = "rm preview/_/css/boostlook.css && cp boostlook-v3.css preview/_/css/boostlook.css"

BIN
notosans.woff2 Normal file

Binary file not shown.

BIN
notosans_ext.woff2 Normal file

Binary file not shown.

75
preview/README.md Normal file
View File

@@ -0,0 +1,75 @@
# Preview Site
Local preview of Boost documentation with boostlook-v3 CSS applied. Deployed to [boostlook-v3.netlify.app](https://boostlook-v3.netlify.app/).
## Prerequisites
- Node.js 16+ (for Antora)
- [asciidoctor](https://asciidoctor.org/) (`brew install asciidoctor`)
- b2 (from the Boost superproject)
- Python 3 (for local server)
Sibling repos expected at:
```
~/dev/website-v2-docs # Antora site & library docs
~/boost # Boost superproject (for b2/charconv)
```
`~/user-config.jam` must contain:
```
using asciidoctor ;
```
## Building
### Full build
Builds everything (Antora lib docs, site docs, charconv via b2), syncs into `preview/`, swaps in `boostlook-v3.css`, and starts a local server:
```
./build-preview.sh
```
### CSS only
Edit CSS in `src/css/`, then rebuild and swap without re-running Antora/b2:
```
./build-preview.sh --css-only
```
### Serve only
Start the local server without rebuilding anything:
```
./build-preview.sh --serve
```
## Structure
```
preview/
index.html Landing page
style-guide/ Design tokens (colors, typography, spacing)
capy/ Boost.Capy library docs (Antora)
charconv/ Boost.Charconv library docs (Asciidoctor + b2)
user-guide/ Site docs (Antora)
contributor-guide/ Site docs (Antora)
formal-reviews/ Site docs (Antora)
_/ Shared assets (fonts, JS, images, CSS)
```
## How it works
1. `build-css.sh` concatenates `src/css/*.css` into `boostlook-v3.css`
2. Antora builds capy + site docs from `website-v2-docs` into its `build/` dir
3. b2 builds charconv HTML from `~/boost/libs/charconv/doc/`, using `boostlook-v3.css` swapped into `~/boost/tools/boostlook/boostlook.css`
4. `rsync` copies built output into `preview/`
5. `boostlook-v3.css` replaces `preview/_/css/boostlook.css` for Antora pages
## Netlify
Netlify deploys from `preview/` on push. The build command in `netlify.toml` only does the CSS swap (Antora/b2 builds are done locally and committed).

5012
preview/_/css/boostlook.css Normal file

File diff suppressed because it is too large Load Diff

3
preview/_/css/site.css Normal file

File diff suppressed because one or more lines are too long

1
preview/_/css/vendor/tabs.css vendored Normal file
View File

@@ -0,0 +1 @@
/*! Asciidoctor Tabs | Copyright (c) 2018-present Dan Allen | MIT License */.tabs{margin-bottom:1.25em}.tablist>ul{-ms-flex-wrap:wrap;flex-wrap:wrap;list-style:none;margin:0;padding:0}.tablist>ul,.tablist>ul li{display:-webkit-box;display:-ms-flexbox;display:flex}.tablist>ul li{-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-color:#fff;cursor:pointer;font-weight:700;line-height:1.5;padding:.25em 1em;position:relative}.tablist>ul li:focus-visible{outline:none}.tablist.ulist,.tablist.ulist>ul li{margin:0}.tablist.ulist>ul li+li{margin-left:.25em}.tabs.is-loading .tablist li:not(:first-child),.tabs:not(.is-loading) .tablist li:not(.is-selected){background-color:#f5f5f5}.tabs.is-loading .tablist li:first-child::after,.tabs:not(.is-loading) .tablist li.is-selected::after{background-color:inherit;content:"";display:block;height:3px;position:absolute;bottom:-1.5px;left:0;right:0}.tablist>ul p{line-height:inherit;margin:0}.tabpanel{background-color:#fff;padding:1.25em}.tablist>ul li,.tabpanel{border:1px solid #dcdcdc}.tablist>ul li{border-bottom:0}.tabs.is-loading .tabpanel+.tabpanel,.tabs:not(.is-loading) .tabpanel.is-hidden{display:none}.tabpanel>:first-child{margin-top:0}#content .tabpanel>:last-child,#content .tabpanel>:last-child>:last-child,#content .tabpanel>:last-child>:last-child>li:last-child>:last-child{margin-bottom:0}.tablecontainer{overflow-x:auto}#content .tablecontainer{margin-bottom:1.25em}#content .tablecontainer>table.tableblock{margin-bottom:0}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2472.56 813.85"><defs><style>.cls-2{fill:#191919}</style></defs><path d="M573.68 259.87a162.91 162.91 0 00-97.41-149.16l-185.72 295.7H98.68L291 97.19H97.43v618.34l193.88-308.8h189.15l-190 309.83h120.32a162.9 162.9 0 00162.9-162.9c0-63.27-39.38-120.06-92.11-147.06a162.9 162.9 0 0092.11-146.73z" fill="#ff9f00"/><path class="cls-2" d="M1178 463.38a114.24 114.24 0 00-14-31.49 103.74 103.74 0 00-49.57-40.61 104.44 104.44 0 0044.48-40.94c11.09-18.64 16.67-40.88 16.67-66.11 0-39.24-12.06-71.28-35.82-95.28s-59.63-36.12-106.66-36.12l-199.13.2v482.21h205.8c45.75 0 81.45-12 106-35.7s37-57.34 37-99.84a135.3 135.3 0 00-4.77-36.32zM907.31 228.66h126.34c22.25 0 39.22 5.58 50.37 16.46s16.66 26.32 16.66 45.91c0 41-22.54 61.69-67 61.69H907.31zm131.13 330.75H907.31V429.3h131.8c21.94 0 39 5.78 50.91 17.07s17.87 27.41 17.87 47.95c0 43.8-22.72 65.09-69.45 65.09zm1124.1-26.61c0 34.91-10.4 61-31 77.46-20 16-50.89 24.26-91.77 24.39h-131.11l21.11-62.19h106.92c20 0 35-3 45-8.79 8.92-5.32 13.22-13.86 13.22-26 0-8.8-2.12-15.34-6.36-19.51-4.62-4.69-10.78-8.22-18.22-10.53l-4.11-1.28a127.85 127.85 0 00-25-6l-14.5-2.44c-23.23-3.72-42-8.47-55.58-14.18-14.44-6-25.67-15.08-33.56-26.83s-11.75-27.66-11.75-47.61a133.94 133.94 0 011.74-22.4c2.18-13.09 6.41-24.64 12.7-34.27 18-28 53.4-42.16 105.38-42.16h108.13v61.8h-104.96V372l-3.27.07c-52.18.83-52.18 23.68-52.18 31.19s2 13.15 6 17c4.5 4.37 10.46 7.58 17.65 9.69 8.09 2.38 37 9.05 45.31 10.66 23.94 4.49 43.06 9.75 56.67 15.66 14.5 6.29 25.54 15.66 32.79 27.91s10.75 28.47 10.75 48.62z"/><path class="cls-2" d="M2039.77 634.65h-131.11l21.11-62.19h106.92c20 0 35-3 45-8.79 8.92-5.32 13.22-13.86 13.22-26 0-8.8-2.12-15.34-6.36-19.51-4.62-4.69-10.78-8.22-18.22-10.53l-4.11-1.28a127.85 127.85 0 00-25-6l-14.5-2.44c-23.23-3.72-42-8.47-55.58-14.18-14.44-6-25.67-15.08-33.56-26.83s-11.75-27.66-11.75-47.61a133.94 133.94 0 011.74-22.4c2.18-13.09 6.41-24.64 12.7-34.27 18-28 53.4-42.16 105.38-42.16h108.13v61.8h-104.96V372l-3.27.07c-52.18.83-52.18 23.68-52.18 31.19s2 13.15 6 17c4.5 4.37 10.46 7.58 17.65 9.69 8.09 2.38 37 9.05 45.31 10.66 23.94 4.49 43.06 9.75 56.67 15.66 14.5 6.29 25.54 15.66 32.79 27.91s10.72 28.43 10.72 48.58c0 34.91-10.4 61-31 77.46-19.99 16.09-50.86 24.3-91.74 24.43zm173.91-408.17l70.66-.19.26 83.55 86.31-.13v61.42l-86.12.19.45 198.18 89.84-.26-22.84 62-96.07.26a41.51 41.51 0 01-41.46-41.39z"/><path class="cls-2" d="M2375.08 569.24l-22.84 62-96.07.26a41.51 41.51 0 01-41.46-41.39l-1-363.62 70.66-.19.26 83.55 86.31-.13v61.42l-86.12.19.45 198.18zM1380.63 306c-52.14 0-90.73 13.92-114.69 41.37-23.76 27.2-35.8 70.47-35.8 128.59 0 56.88 11.81 99.4 35.11 126.38 23.54 27.27 62.36 41.09 115.38 41.09S1472.49 629.5 1496 602c23.29-27.2 35.1-69.61 35.1-126 0-57.68-11.92-100.82-35.43-128.23-23.75-27.72-62.47-41.77-115.04-41.77zm-67.8 103.79c4.52-14.68 12-25.15 22.37-31.12 10.78-6.22 26.07-9.38 45.43-9.38s34.51 3.15 45.06 9.36c10.14 6 17.57 16.35 22.1 30.86 4.82 15.49 7.27 37.85 7.27 66.45 0 27.4-2.34 48.94-7 64-4.38 14.3-11.52 24.3-21.83 30.55-10.53 6.4-25.88 9.64-45.64 9.64s-35.26-3.25-46-9.67c-10.5-6.24-17.73-16.32-22.11-30.81-4.62-15.24-7-36.68-7-63.71.07-28.22 2.52-50.48 7.35-66.16zm530.76-62.05c-23.78-27.69-62.49-41.74-115.06-41.74-52.15 0-90.74 13.92-114.7 41.37-23.76 27.2-35.8 70.47-35.8 128.59 0 56.88 11.81 99.4 35.11 126.38 23.54 27.27 62.36 41.09 115.39 41.09s91.85-13.94 115.39-41.42c23.29-27.2 35.1-69.61 35.1-126-.02-57.72-11.92-100.86-35.43-128.27zM1802.94 476c0 27.42-2.33 48.95-7 64-4.38 14.3-11.52 24.3-21.83 30.55-10.52 6.4-25.88 9.64-45.63 9.64s-35.27-3.25-46-9.67c-10.5-6.24-17.73-16.32-22.11-30.81-4.62-15.25-7-36.68-7-63.71 0-28.23 2.45-50.49 7.28-66.17 4.52-14.68 12-25.15 22.37-31.12 10.79-6.22 26.07-9.38 45.44-9.38s34.5 3.15 45 9.36c10.14 6 17.57 16.35 22.1 30.86 4.94 15.45 7.38 37.81 7.38 66.45z"/></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1 @@
<svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 670 813.85"><path d="M573.08 259.87a162.89 162.89 0 00-97.41-149.16L290 406.41H98.08L290.42 97.19H96.84v618.34l193.87-308.8h189.15l-190 309.83h120.32a162.9 162.9 0 00162.9-162.9c0-63.27-39.37-120.06-92.1-147.06a162.89 162.89 0 0092.1-146.73z" fill="#ff9f00"/></svg>

After

Width:  |  Height:  |  Size: 338 B

View File

@@ -0,0 +1 @@
<svg width="28" height="28" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M27.333 10.667v6.666h-15l5.834 5.834-4.034 4.033L.933 14 14.133.8l4.034 4.033-5.834 5.834h15z" fill="#000"/></svg>

After

Width:  |  Height:  |  Size: 198 B

View File

@@ -0,0 +1 @@
<svg width="28" height="28" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M.667 10.667v6.666h15l-5.834 5.834 4.034 4.033 13.2-13.2L13.867.8 9.833 4.833l5.834 5.834h-15z" fill="#000"/></svg>

After

Width:  |  Height:  |  Size: 199 B

View File

@@ -0,0 +1 @@
<svg width="28" height="28" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M17.333 27.333h-6.666v-15l-5.834 5.834L.8 14.133 14 .933l13.2 13.2-4.033 4.034-5.834-5.834v15z" fill="#000"/></svg>

After

Width:  |  Height:  |  Size: 199 B

1
preview/_/img/back.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M50.001 9.9L9.9 50 50 90.1l5.656-5.655-30.435-30.442H90.1v-8.006H25.222l30.435-30.44z"/></svg>

After

Width:  |  Height:  |  Size: 190 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1500 1500"><path d="M1100 143.77H400L50 750l94.89 164.36L494.75 308.2h353.59c150.74 0 273.32 122.59 273.32 273.33 0 64.13-26.58 138.57-81.41 169.77 53.38 40.17 79.17 104.07 79.17 166.79 0 150.66-122.59 273.25-273.33 273.25H382.46l121.09-209.87h342.53c35.02 0 63.46-28.44 63.46-63.39s-26.8-61.82-60.47-63.31c-.97-.15-272.36 0-272.36 0l121.25-210.01s151.93.15 152.6.07c14.26-.45 27.25-5.6 37.56-14.04 14.48-11.57 23.67-29.34 23.67-49.27 0-35.01-28.45-63.46-63.46-63.46H622.7l-353.36 611.93 130.65 226.24h700l350-606.23-350-606.23z" fill="#ff9f00"/></svg>

After

Width:  |  Height:  |  Size: 605 B

1
preview/_/img/caret.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30"><path d="M10.187 3l14 12-14 12z" fill="#c1c1c1" stroke="#c1c1c1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>

After

Width:  |  Height:  |  Size: 219 B

View File

@@ -0,0 +1 @@
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)"><path d="M15.8 12.526L9.483.88A1.668 1.668 0 008.8.2a1.693 1.693 0 00-2.284.68L.2 12.526A1.678 1.678 0 001.686 15h12.628a1.7 1.7 0 001.308-.615 1.67 1.67 0 00.178-1.859zM8 13a1 1 0 110-2 1 1 0 010 2zm1-3.5a.5.5 0 01-.5.5h-1a.5.5 0 01-.5-.5v-4a.5.5 0 01.5-.5h1a.5.5 0 01.5.5v4z" fill="#FF9100"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 480 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30"><path d="M3.67 6.59L1.455 8.615 15 23.375l13.545-14.76L26.33 6.59 15 18.76z" fill="#5d5d5d"/></svg>

After

Width:  |  Height:  |  Size: 182 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path fill="#ddd" d="M50.001 9.9L9.9 50 50 90.1l5.656-5.655-30.435-30.442H90.1v-8.006H25.222l30.435-30.44z"/></svg>

After

Width:  |  Height:  |  Size: 202 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M35 19.772h55" fill="none" stroke="#ddd" stroke-width="8" stroke-opacity=".941"/><path fill="#ddd" d="M10 12.272h15v15H10z"/><path d="M43 63.678h45" fill="none" stroke="#ddd" stroke-width="5" stroke-opacity=".941"/><path fill="#ddd" d="M23 58.677h10v10H23z"/><path d="M43 82.727h45" fill="none" stroke="#ddd" stroke-width="5" stroke-opacity=".941"/><path fill="#ddd" d="M23 77.727h10v10H23z"/><path d="M43 44.628h45" fill="none" stroke="#ddd" stroke-width="5" stroke-opacity=".941"/><path fill="#ddd" d="M23 39.628h10v10H23z"/></svg>

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 955 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

1
preview/_/img/home-o.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><g fill="none" stroke="#222" stroke-width="4"><path d="M50.02 13.576l-28.58 25.54-.02 47.345h21.506l.025-25.166H57.05l.025 25.166H78.62l.02-47.31-28.62-25.575z"/><path d="M63.815 25.904v-9.217h8.657V33.64zM21.439 39.116l-9.982 8.92m77.125 0l-9.943-8.885"/></g></svg>

After

Width:  |  Height:  |  Size: 328 B

BIN
preview/_/img/home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

1
preview/_/img/home.svg Normal file
View File

@@ -0,0 +1 @@
<svg width="34" height="29" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.667 28.333v-10h6.666v10h8.334V15h5L17 0 .333 15h5v13.333h8.334z" fill="#000"/></svg>

After

Width:  |  Height:  |  Size: 172 B

View File

@@ -0,0 +1 @@
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)"><path d="M7.75 0A7.749 7.749 0 000 7.75a7.749 7.749 0 007.75 7.75 7.749 7.749 0 007.75-7.75A7.749 7.749 0 007.75 0z" fill="#EED202"/><path d="M9.488 11.3a1.501 1.501 0 11-1.5-1.5c.827 0 1.5.673 1.5 1.5zM6.66 3.672l.255 5.1a.45.45 0 00.45.428h1.243a.45.45 0 00.45-.428l.255-5.1a.45.45 0 00-.45-.472H7.111a.45.45 0 00-.45.472z" fill="#fff"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 525 B

1
preview/_/img/menu.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M35 19.772h55" fill="none" stroke="#222" stroke-width="8" stroke-opacity=".941"/><path fill="#222" d="M10 12.272h15v15H10z"/><path d="M43 63.678h45" fill="none" stroke="#222" stroke-width="5" stroke-opacity=".941"/><path fill="#222" d="M23 58.677h10v10H23z"/><path d="M43 82.727h45" fill="none" stroke="#222" stroke-width="5" stroke-opacity=".941"/><path fill="#222" d="M23 77.727h10v10H23z"/><path d="M43 44.628h45" fill="none" stroke="#222" stroke-width="5" stroke-opacity=".941"/><path fill="#222" d="M23 39.628h10v10H23z"/></svg>

After

Width:  |  Height:  |  Size: 604 B

BIN
preview/_/img/next.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

1
preview/_/img/note.svg Normal file
View File

@@ -0,0 +1 @@
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.75 2A1.75 1.75 0 000 3.75v8.5A1.75 1.75 0 001.75 14h12.5A1.75 1.75 0 0016 12.25v-8.5A1.75 1.75 0 0014.25 2H1.75z" fill="#217EE7"/><path d="M2.258 5.244a.81.81 0 00-.258.59.81.81 0 00.258.589.91.91 0 00.624.244h8.236a.91.91 0 00.624-.244.81.81 0 00.258-.59.81.81 0 00-.258-.589.91.91 0 00-.624-.244H2.882a.91.91 0 00-.624.244zm5.33 3.089H2.882a.91.91 0 00-.624.244.81.81 0 00-.258.59.81.81 0 00.258.589.91.91 0 00.624.244h4.706a.91.91 0 00.624-.244.81.81 0 00.259-.59.81.81 0 00-.259-.589.91.91 0 00-.624-.244z" fill="#fff"/><path d="M0 3.75C0 2.784.784 2 1.75 2h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0114.25 14H1.75A1.75 1.75 0 010 12.25v-8.5zm1.75-.25a.25.25 0 00-.25.25v8.5c0 .138.112.25.25.25h12.5a.25.25 0 00.25-.25v-8.5a.25.25 0 00-.25-.25H1.75z" fill="#217EE7"/></svg>

After

Width:  |  Height:  |  Size: 870 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><desc>Octicons v11.2.0 by GitHub - https://primer.style/octicons/ - License: MIT</desc><symbol id="icon-clippy" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"/></symbol><use href="#icon-clippy" width="16" height="16"/><view id="view-clippy" viewBox="0 0 16 16"/></svg>

After

Width:  |  Height:  |  Size: 710 B

BIN
preview/_/img/prev.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

1
preview/_/img/tip.svg Normal file
View File

@@ -0,0 +1 @@
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M6 14c0 .333.267.667.667.667h2.666c.4 0 .667-.334.667-.667v-.667H6V14zM8 1.333A4.638 4.638 0 003.333 6c0 1.6.8 3 2 3.8v1.533c0 .334.267.667.667.667h4c.4 0 .667-.333.667-.667V9.8c1.2-.867 2-2.267 2-3.8 0-2.6-2.067-4.667-4.667-4.667z" fill="#5CB85C"/></svg>

After

Width:  |  Height:  |  Size: 339 B

BIN
preview/_/img/up.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

View File

@@ -0,0 +1 @@
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)"><path d="M1 4.862L5 1h6l4 3.862v5.793L10.5 15h-5L1 10.655V4.862z" fill="#FF5252"/><path d="M8.53 4.22a.75.75 0 00-1.28.53v3.5a.75.75 0 001.5 0v-3.5a.75.75 0 00-.22-.53zm-1.237 7.487a1 1 0 101.414-1.414 1 1 0 00-1.414 1.414z" fill="#fff"/><path d="M15 5l-4-4H5L1 5v6l4 4h6l4-4V5z" stroke="#FF5252"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 484 B

7
preview/_/js/site.js Normal file
View File

@@ -0,0 +1,7 @@
!function(){"use strict";var t,a,d,i,e,n;function r(e){"dark"===e?d.classList.add(a):d.classList.remove(a)}function c(){var e="dark"==(d.classList.contains(a)?"dark":"light")?"light":"dark";r(e),i.setItem(t,e)}window.self===window.top&&(t="antora-theme",a="dark",d=document.documentElement,i=window.localStorage,r(i.getItem(t)||(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light")),(n=document.querySelector(".theme-toggle"))&&(n.style.display="inline-flex",n.addEventListener("click",c)),window.matchMedia)&&(n=function(e){i.getItem(t)||r(e.matches?"dark":"light")},(e=window.matchMedia("(prefers-color-scheme: dark)")).addEventListener?e.addEventListener("change",n):e.addListener&&e.addListener(n))}();
!function(){"use strict";var s,o,r=/^sect(\d)$/,t=document.querySelector(".nav-container"),n=document.querySelector(".nav-toggle"),a=t.querySelector(".nav"),e=t.querySelector(".nav-close"),l=(n.addEventListener("click",function(e){if(n.classList.contains("is-active"))return u(e);v(e);e=document.documentElement;e.classList.add("is-clipped--nav"),n.classList.add("is-active"),t.classList.add("is-active"),e.addEventListener("click",u)}),t.addEventListener("click",v),e.addEventListener("click",u),t.querySelector("[data-panel=menu]"));function i(){var e,t,n=window.location.hash;if(n&&(n.indexOf("%")&&(n=decodeURIComponent(n)),!(e=l.querySelector('.nav-link[href="'+n+'"]')))){n=document.getElementById(n.slice(1));if(n)for(var i=n,c=document.querySelector("article.doc");(i=i.parentNode)&&i!==c;){var a=i.id;if((a=a||(a=r.test(i.className))&&(i.firstElementChild||{}).id)&&(e=l.querySelector('.nav-link[href="#'+a+'"]')))break}}if(e)t=e.parentNode;else{if(!o)return;e=(t=o).querySelector(".nav-link")}t!==s&&(m(l,".is-active, .is-current-path, .is-current-page").forEach(function(e){e.classList.remove("is-active","is-current-path","is-current-page")}),t.classList.add("is-current-page"),d(s=t),p(l,e))}function d(e){for(var t,n=e.parentNode;!(t=n.classList).contains("nav-menu");)"LI"===n.tagName&&t.add("is-active","is-current-path"),n=n.parentNode;e.classList.add("is-active")}function c(){var e,t,n,i;this.classList.toggle("is-active")&&(e=parseFloat(window.getComputedStyle(this).marginTop),t=this.getBoundingClientRect(),n=l.getBoundingClientRect(),0<(i=(t.bottom-n.top-n.height+e).toFixed()))&&(l.scrollTop+=Math.min((t.top-n.top-e).toFixed(),i))}function u(e){v(e);e=document.documentElement;e.classList.remove("is-clipped--nav"),n.classList.remove("is-active"),t.classList.remove("is-active"),e.removeEventListener("click",u)}function v(e){e.stopPropagation()}function p(e,t){var n=e.getBoundingClientRect(),i=n.height,c=window.getComputedStyle(a);"sticky"===c.position&&(i-=n.top-parseFloat(c.top)),e.scrollTop=Math.max(0,.5*(t.getBoundingClientRect().height-i)+t.offsetTop)}function m(e,t){return[].slice.call(e.querySelectorAll(t))}l&&(e=t.querySelector("[data-panel=explore]"),s=l.querySelector(".is-current-page"),(o=s)?(d(s),p(l,s.querySelector(".nav-link"))):l.scrollTop=0,m(l,".nav-item-toggle").forEach(function(e){var t=e.parentElement,e=(e.addEventListener("click",c.bind(t)),function(e,t){e=e.nextElementSibling;return(!e||!t||e[e.matches?"matches":"msMatchesSelector"](t))&&e}(e,".nav-text"));e&&(e.style.cursor="pointer",e.addEventListener("click",c.bind(t)))}),e&&e.querySelector(".context").addEventListener("click",function(){m(a,"[data-panel]").forEach(function(e){e.classList.toggle("is-active")})}),l.addEventListener("mousedown",function(e){1<e.detail&&e.preventDefault()}),window.addEventListener("resize",function(){var e=document.documentElement;769<=window.innerWidth&&e.classList.contains("is-clipped--nav")&&(e.classList.remove("is-clipped--nav"),t.classList.remove("is-active"),n.classList.remove("is-active"))}),l.querySelector('.nav-link[href^="#"]'))&&(window.location.hash&&i(),window.addEventListener("hashchange",i))}();
!function(){"use strict";var e=document.querySelector("aside.toc.sidebar");if(e){if(document.querySelector("body.-toc"))return e.parentNode.removeChild(e);var t=parseInt(e.dataset.levels||2,10);if(!(t<0)){for(var o="article.doc",d=document.querySelector(o),n=[],i=0;i<=t;i++){var r=[o];if(i){for(var c=1;c<=i;c++)r.push((2===c?".sectionbody>":"")+".sect"+c);r.push("h"+(i+1)+"[id]")}else r.push("h1[id].sect0");n.push(r.join(">"))}m=n.join(","),f=d.parentNode;var a,s=[].slice.call((f||document).querySelectorAll(m));if(!s.length)return e.parentNode.removeChild(e);var l={},u=s.reduce(function(e,t){var o=document.createElement("a"),n=(o.textContent=t.textContent,l[o.href="#"+t.id]=o,document.createElement("li"));return n.dataset.level=parseInt(t.nodeName.slice(1),10)-1,n.appendChild(o),e.appendChild(n),e},document.createElement("ul")),f=e.querySelector(".toc-menu"),m=(f||((f=document.createElement("div")).className="toc-menu"),document.createElement("h3")),e=(m.textContent=e.dataset.title||"Contents",f.appendChild(m),f.appendChild(u),!document.getElementById("toc")&&d.querySelector("h1.page ~ :not(.is-before-toc)"));e&&((m=document.createElement("aside")).className="toc embedded",m.appendChild(f.cloneNode(!0)),e.parentNode.insertBefore(m,e)),window.addEventListener("load",function(){p(),window.addEventListener("scroll",p)})}}function p(){var n,i,t,e=window.pageYOffset,o=1.15*h(document.documentElement,"fontSize"),r=d.offsetTop;e&&window.innerHeight+e+2>=document.documentElement.scrollHeight?(a=Array.isArray(a)?a:Array(a||0),n=[],i=s.length-1,s.forEach(function(e,t){var o="#"+e.id;t===i||e.getBoundingClientRect().top+h(e,"paddingTop")>r?(n.push(o),a.indexOf(o)<0&&l[o].classList.add("is-active")):~a.indexOf(o)&&l[a.shift()].classList.remove("is-active")}),u.scrollTop=u.scrollHeight-u.offsetHeight,a=1<n.length?n:n[0]):(Array.isArray(a)&&(a.forEach(function(e){l[e].classList.remove("is-active")}),a=void 0),s.some(function(e){if(e.getBoundingClientRect().top+h(e,"paddingTop")-o>r)return!0;t="#"+e.id}),t?t!==a&&(a&&l[a].classList.remove("is-active"),(e=l[t]).classList.add("is-active"),u.scrollHeight>u.offsetHeight&&(u.scrollTop=Math.max(0,e.offsetTop+e.offsetHeight-u.offsetHeight)),a=t):a&&(l[a].classList.remove("is-active"),a=void 0))}function h(e,t){return parseFloat(window.getComputedStyle(e)[t])}}();
!function(){"use strict";var o=document.querySelector("article.doc"),t=document.querySelector(".toolbar");function i(e){return e&&(~e.indexOf("%")?decodeURIComponent(e):e).slice(1)}function r(e){if(e){if(e.altKey||e.ctrlKey)return;window.location.hash="#"+this.id,e.preventDefault()}window.scrollTo(0,function e(t,n){return o.contains(t)?e(t.offsetParent,t.offsetTop+n):n}(this,0)-t.getBoundingClientRect().bottom)}window.addEventListener("load",function e(t){var n;(n=i(window.location.hash))&&(n=document.getElementById(n))&&(r.bind(n)(),setTimeout(r.bind(n),0)),window.removeEventListener("load",e)}),Array.prototype.slice.call(document.querySelectorAll('a[href^="#"]')).forEach(function(e){var t;(t=i(e.hash))&&(t=document.getElementById(t))&&e.addEventListener("click",r.bind(t))})}();
!function(){"use strict";var t,e=document.querySelector(".page-versions .version-menu-toggle");e&&(t=document.querySelector(".page-versions"),e.addEventListener("click",function(e){t.classList.toggle("is-active"),e.stopPropagation()}),document.documentElement.addEventListener("click",function(){t.classList.remove("is-active")}))}();
!function(){"use strict";var t=document.querySelector(".navbar-burger");t&&t.addEventListener("click",function(t){t.stopPropagation(),document.documentElement.classList.toggle("is-clipped--navbar"),this.classList.toggle("is-active");t=document.getElementById(this.dataset.target);{var e;t.classList.toggle("is-active")&&(t.style.maxHeight="",e=window.innerHeight-Math.round(t.getBoundingClientRect().top),parseInt(window.getComputedStyle(t).maxHeight,10)!==e)&&(t.style.maxHeight=e+"px")}}.bind(t))}();
!function(){"use strict";var o=/^\$ (\S[^\\\n]*(\\\n(?!\$ )[^\\\n]*)*)(?=\n|$)/gm,s=/( ) *\\\n *|\\\n( ?) */g,l=/ +$/gm,e=(document.getElementById("site-script")||{dataset:{}}).dataset,d=null==e.uiRootPath?".":e.uiRootPath,r=e.svgAs,p=window.navigator.clipboard;[].slice.call(document.querySelectorAll(".doc pre.highlight, .doc .literalblock pre")).forEach(function(e){var t,n,a,c;if(e.classList.contains("highlight"))(i=(t=e.querySelector("code")).dataset.lang)&&"console"!==i&&((a=document.createElement("span")).className="source-lang",a.appendChild(document.createTextNode(i)));else{if(!e.innerText.startsWith("$ "))return;var i=e.parentNode.parentNode;i.classList.remove("literalblock"),i.classList.add("listingblock"),e.classList.add("highlightjs","highlight"),(t=document.createElement("code")).className="language-console hljs",t.dataset.lang="console",t.appendChild(e.firstChild),e.appendChild(t)}(i=document.createElement("div")).className="source-toolbox",a&&i.appendChild(a),p&&((n=document.createElement("button")).className="copy-button",n.setAttribute("title","Copy to clipboard"),"svg"===r?((a=document.createElementNS("http://www.w3.org/2000/svg","svg")).setAttribute("class","copy-icon"),(c=document.createElementNS("http://www.w3.org/2000/svg","use")).setAttribute("href",d+"/img/octicons-16.svg#icon-clippy"),a.appendChild(c),n.appendChild(a)):((c=document.createElement("img")).src=d+"/img/octicons-16.svg#view-clippy",c.alt="copy icon",c.className="copy-icon",n.appendChild(c)),(a=document.createElement("span")).className="copy-toast",a.appendChild(document.createTextNode("Copied!")),n.appendChild(a),i.appendChild(n)),e.parentNode.appendChild(i),n&&n.addEventListener("click",function(e){var t=e.innerText.replace(l,"");"console"===e.dataset.lang&&t.startsWith("$ ")&&(t=function(e){var t,n=[];for(;t=o.exec(e);)n.push(t[1].replace(s,"$1$2"));return n.join(" && ")}(t));window.navigator.clipboard.writeText(t).then(function(){this.classList.add("clicked"),this.offsetHeight,this.classList.remove("clicked")}.bind(this),function(){})}.bind(n,t))})}();

1
preview/_/js/vendor/cpp-highlight.js vendored Normal file
View File

@@ -0,0 +1 @@
const CppHighlight=function(){"use strict";const o=new Set(["auto","register","static","extern","mutable","thread_local","const","volatile","constexpr","consteval","constinit","void","bool","char","short","int","long","float","double","signed","unsigned","wchar_t","char8_t","char16_t","char32_t","class","struct","union","enum","typename","typedef","if","else","switch","case","default","for","while","do","break","continue","return","goto","try","catch","throw","noexcept","public","private","protected","virtual","override","final","friend","this","operator","new","delete","template","concept","requires","namespace","using","sizeof","alignof","alignas","decltype","typeid","static_cast","dynamic_cast","const_cast","reinterpret_cast","static_assert","inline","explicit","export","module","import","co_await","co_yield","co_return","true","false","nullptr","NULL"]);function a(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function u(e,t){return`<span class="cpp-${e}">${a(t)}</span>`}function t(i){var r=[];let l=0;for(var n=i.length;l<n;)if("["===i[l]&&"["===i[l+1]){var t=l;l+=2;let e=1;for(;l<n&&0<e;)"["===i[l]&&"["===i[l+1]?(e++,l+=2):"]"===i[l]&&"]"===i[l+1]?(e--,l+=2):l++;r.push(u("attribute",i.slice(t,l)))}else if("/"===i[l]&&"/"===i[l+1]){let e=l+2;for(;e<n&&"\n"!==i[e];)e++;r.push(u("comment",i.slice(l,e))),l=e}else if("/"===i[l]&&"*"===i[l+1]){let e=l+2;for(;e<n-1&&("*"!==i[e]||"/"!==i[e+1]);)e++;e+=2,r.push(u("comment",i.slice(l,e))),l=e}else{if("#"===i[l]){let e=l-1;for(;0<=e&&(" "===i[e]||"\t"===i[e]);)e--;if(e<0||"\n"===i[e]){let e=l+1;for(;e<n;){if("\n"===i[e])if("\\"!==i[e-1])break;e++}r.push(u("preprocessor",i.slice(l,e))),l=e;continue}}if("R"===i[l]&&'"'===i[l+1]){let e=l+2;for(;e<n&&"("!==i[e];)e++;var s=")"+i.slice(l+2,e)+'"';let t=e+1;for(;t<n;){if(i.slice(t,t+s.length)===s){t+=s.length;break}t++}r.push(u("string",i.slice(l,t))),l=t}else if('"'===i[l]||("L"===i[l]||"u"===i[l]||"U"===i[l])&&'"'===i[l+1]||"u"===i[l]&&"8"===i[l+1]&&'"'===i[l+2]){t=l;for("u"===i[l]&&"8"===i[l+1]?l+=2:'"'!==i[l]&&l++,l++;l<n&&'"'!==i[l];)"\\"===i[l]&&l+1<n?l+=2:l++;l++,r.push(u("string",i.slice(t,l)))}else if("'"===i[l]||("L"===i[l]||"u"===i[l]||"U"===i[l])&&"'"===i[l+1]||"u"===i[l]&&"8"===i[l+1]&&"'"===i[l+2]){var c=l;for("u"===i[l]&&"8"===i[l+1]?l+=2:"'"!==i[l]&&l++,l++;l<n&&"'"!==i[l];)"\\"===i[l]&&l+1<n?l+=2:l++;l++,r.push(u("string",i.slice(c,l)))}else if(/[a-zA-Z_]/.test(i[l])){let e=l+1;for(;e<n&&/[a-zA-Z0-9_]/.test(i[e]);)e++;c=i.slice(l,e);o.has(c)?r.push(u("keyword",c)):r.push(a(c)),l=e}else r.push(a(i[l])),l++}return r.join("")}function i(e){e.innerHTML=t(e.textContent)}return{highlight:t,highlightElement:i,highlightAll:function(e="code.cpp, code.c++, pre.cpp, pre.c++"){document.querySelectorAll(e).forEach(i)},KEYWORDS:o}}();"undefined"!=typeof module&&module.exports&&(module.exports=CppHighlight);

1
preview/_/js/vendor/highlight.js vendored Normal file

File diff suppressed because one or more lines are too long

2
preview/_/js/vendor/tabs.js vendored Normal file
View File

@@ -0,0 +1,2 @@
!function(){/*! Asciidoctor Tabs | Copyright (c) 2018-present Dan Allen | MIT License */
"use strict";var t,r=(document.currentScript||{}).dataset||{},d=Array.prototype.forEach;function u(t){var e,a=this.tab,n=this.tabs||(this.tabs=a.closest(".tabs")),i=this.panel||(this.panel=document.getElementById(a.getAttribute("aria-controls")));d.call(n.querySelectorAll(".tablist .tab"),function(t){p(t,t===a)}),d.call(n.querySelectorAll(".tabpanel"),function(t){y(t,t!==i)}),!this.isSync&&"syncStorageKey"in r&&"syncGroupId"in n.dataset&&(n=r.syncStorageKey+"-"+n.dataset.syncGroupId,window[(r.syncStorageScope||"local")+"Storage"].setItem(n,a.dataset.syncId)),t&&(~(e=(n=window.location).hash?n.href.indexOf("#"):-1)&&window.history.replaceState(null,"",n.href.slice(0,e)),t.preventDefault())}function b(t){u.call(this,t);var a=this.tabs,n=this.tab,t=a.getBoundingClientRect().y,t=(d.call(document.querySelectorAll(".tabs"),function(e){e!==a&&e.dataset.syncGroupId===a.dataset.syncGroupId&&d.call(e.querySelectorAll(".tablist .tab"),function(t){t.dataset.syncId===n.dataset.syncId&&u.call({tabs:e,tab:t,isSync:!0})})}),a.getBoundingClientRect().y-t);(t=t&&Math.round(t))&&window.scrollBy({top:t,behavior:"instant"})}function e(t,e,a){d.call(t,function(t){t.classList[a](e)})}function y(t,e){t.classList[(t.hidden=e)?"add":"remove"]("is-hidden")}function p(t,e){t.setAttribute("aria-selected",""+e),t.classList[e?"add":"remove"]("is-selected"),t.tabIndex=e?0:-1}function a(){var t=window.location.hash.slice(1);t&&(t=document.getElementById(~t.indexOf("%")?decodeURIComponent(t):t))&&t.classList.contains("tab")&&("syncId"in t.dataset?b:u).call({tab:t})}(t=document.querySelectorAll(".tabs")).length&&(d.call(t,function(s){var l,o=s.classList.contains("is-sync")?{}:void 0,t=s.querySelector(".tablist ul");if(t.setAttribute("role","tablist"),d.call(t.querySelectorAll("li"),function(t,e){var a,n;if(t.setAttribute("role",t.className="tab"),!(a=t.id)){if(!(i=t.querySelector("a[id]")))return;t.id=a=i.parentNode.removeChild(i).id}var i=s.querySelector('.tabpanel[aria-labelledby~="'+a+'"]');i&&(t.tabIndex=-1,o&&((n=t.textContent.trim())in o?n=void 0:o[t.dataset.syncId=n]=t),e||(l={tab:t,panel:i},o)?y(i,!0):p(t,!0),t.setAttribute("aria-controls",i.id),i.setAttribute("role","tabpanel"),d.call(i.querySelectorAll("table.tableblock"),function(t){var e=Object.assign(document.createElement("div"),{className:"tablecontainer"});t.parentNode.insertBefore(e,t).appendChild(t)}),t.addEventListener("click",(void 0===n?u:b).bind({tabs:s,tab:t,panel:i})))}),o&&l){for(var e,a,n=0,i=s.classList,c=i.length;n!==c;n++)if((a=i.item(n)).startsWith("data-sync-group-id=")){s.dataset.syncGroupId=e=i.remove(a)||a.slice(19).replace(/\u00a0/g," ");break}void 0===e&&(s.dataset.syncGroupId=e=Object.keys(o).sort().join("|"));t="syncStorageKey"in r&&window[(r.syncStorageScope||"local")+"Storage"].getItem(r.syncStorageKey+"-"+e),t=t&&o[t];t&&Object.assign(l,{tab:t,panel:document.getElementById(t.getAttribute("aria-controls"))}),p(l.tab,!0),y(l.panel,!1)}}),a(),e(t,"is-loading","remove"),window.setTimeout(e.bind(null,t,"is-loaded","add"),0),window.addEventListener("hashchange",a))}();

View File

@@ -0,0 +1,386 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Introduction To C&#43;&#43;20 Coroutines :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/2.cpp20-coroutines/2.intro.html">
<link rel="prev" href="../quick-start.html">
<link rel="next" href="2a.foundations.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class=" is-current-page" data-depth="1">
<a class="nav-link" href="2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../4.coroutines/4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="../quick-start.html">
<span class="material-symbols-outlined" title="Previous: Quick Start">arrow_back</span>
</a>
<a class="disabled" accesskey="u" aria-disabled="true" tabindex="-1">
<span class="material-symbols-outlined" title="Up:">arrow_upward</span>
</a>
<a accesskey="n" href="2a.foundations.html">
<span class="material-symbols-outlined" title="Next: Part I: Foundations">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Introduction To C&#43;&#43;20 Coroutines</h1>
<div class="paragraph">
<p>Every C&#43;&#43; function you have ever written follows the same contract: it runs from start to finish, then returns. The caller waits. The stack frame lives and dies in lockstep with that single invocation. This model has served us well for decades, but it forces a hard tradeoff when programs need to wait&#8212;&#8203;for a network response, a disk read, a timer, or another thread. The function either blocks (wasting a thread) or you restructure your code into callbacks, state machines, or futures that scatter your logic across multiple places.</p>
</div>
<div class="paragraph">
<p>C&#43;&#43;20 coroutines change the rules. A coroutine can <em>suspend</em> its execution&#8212;&#8203;saving its local state somewhere outside the stack&#8212;&#8203;and <em>resume</em> later, picking up exactly where it left off. The control flow reads top-to-bottom, like the synchronous code you already know, but the runtime behavior is asynchronous. No blocked threads. No callback chains. No lost context.</p>
</div>
<div class="paragraph">
<p>This is not a minor syntactic convenience. It is a fundamental shift in how you can structure programs that wait.</p>
</div>
<div class="paragraph">
<p>This section takes you from zero to a working understanding of C&#43;&#43;20 coroutines. No prior experience with coroutines or async programming is needed. You will start with the problem that coroutines solve, move through the language syntax and compiler machinery, and finish with the performance characteristics that make coroutines practical for real systems. By the end, you will understand not only <em>how</em> to write coroutines but <em>why</em> they work the way they do&#8212;&#8203;knowledge that will make everything in the rest of this documentation click into place.</p>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/2.cpp20-coroutines/2.intro.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="../quick-start.html">Quick Start</a></span>
<span class="next"><a href="2a.foundations.html">Part I: Foundations</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,615 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Part I: Foundations :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/2.cpp20-coroutines/2a.foundations.html">
<link rel="prev" href="2.intro.html">
<link rel="next" href="2b.syntax.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../4.coroutines/4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a></li>
<li><a href="2a.foundations.html">Part I: Foundations</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="2.intro.html">
<span class="material-symbols-outlined" title="Previous: Introduction To C&#43;&#43;20 Coroutines">arrow_back</span>
</a>
<a accesskey="u" href="2.intro.html">
<span class="material-symbols-outlined" title="Up: Introduction To C&#43;&#43;20 Coroutines">arrow_upward</span>
</a>
<a accesskey="n" href="2b.syntax.html">
<span class="material-symbols-outlined" title="Next: Part II: C&#43;&#43;20 Syntax">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Part I: Foundations</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section introduces the fundamental concepts you need before working with C&#43;&#43;20 coroutines. You will learn how normal functions work, what makes coroutines different, and why coroutines exist as a language feature.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Before beginning this tutorial, you should have:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A C&#43;&#43; compiler with C&#43;&#43;20 support (GCC 10+, Clang 14+, or MSVC 2019 16.8+)</p>
</li>
<li>
<p>Familiarity with basic C&#43;&#43; concepts: functions, classes, templates, and lambdas</p>
</li>
<li>
<p>Understanding of how function calls work: the call stack, local variables, and return values</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The examples in this tutorial use standard C&#43;&#43;20 features. Compile with:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>GCC: <code>g -std=c20 -fcoroutines your_file.cpp</code></p>
</li>
<li>
<p>Clang: <code>clang -std=c20 your_file.cpp</code></p>
</li>
<li>
<p>MSVC: <code>cl /std:c++20 your_file.cpp</code></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_functions_and_the_call_stack"><a class="anchor" href="#_functions_and_the_call_stack"></a>Functions and the Call Stack</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When you call a regular function, the system allocates space on the <strong>call stack</strong> for the function&#8217;s local variables and parameters. This stack space is called a <strong>stack frame</strong>. When the function returns, this stack space is reclaimed. The function&#8217;s state exists only during the call.</p>
</div>
<div class="paragraph">
<p>Consider this function:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">int compute(int x, int y)
{
int result = x * y + 42;
return result;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>When <code>compute</code> is called:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>A stack frame is allocated containing <code>x</code>, <code>y</code>, and <code>result</code></p>
</li>
<li>
<p>The function body executes</p>
</li>
<li>
<p>The return value is passed back to the caller</p>
</li>
<li>
<p>The stack frame is deallocated</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>This model has a fundamental constraint: <strong>run-to-completion</strong>. Once a function starts, it must finish before control returns to the caller. The function cannot pause midway, let other code run, and resume later.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_what_is_a_coroutine"><a class="anchor" href="#_what_is_a_coroutine"></a>What Is a Coroutine?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A <strong>coroutine</strong> is a function that can suspend its execution and resume later from exactly where it left off. Think of it as a bookmark in a book of instructions—instead of reading the entire book in one sitting, you can mark your place, do something else, and return to continue reading.</p>
</div>
<div class="paragraph">
<p>When a coroutine suspends:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Its local variables are preserved</p>
</li>
<li>
<p>The instruction pointer (where you are in the code) is saved</p>
</li>
<li>
<p>Control returns to the caller or some other code</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>When a coroutine resumes:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Local variables are restored to their previous values</p>
</li>
<li>
<p>Execution continues from the suspension point</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This capability is implemented through a <strong>coroutine frame</strong>—a heap-allocated block of memory that stores the coroutine&#8217;s state. Unlike stack frames, coroutine frames persist across suspension points because they live on the heap rather than the stack.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">// Conceptual illustration (not real syntax)
task&lt;int&gt; fetch_and_process()
{
auto data = co_await fetch_from_network(); // suspends here
// When resumed, 'data' contains the fetched result
return process(data);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The variable <code>data</code> maintains its value even though the function may have suspended and resumed. This is the fundamental capability that coroutines provide.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_why_coroutines"><a class="anchor" href="#_why_coroutines"></a>Why Coroutines?</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_the_problem_asynchronous_programming_without_coroutines"><a class="anchor" href="#_the_problem_asynchronous_programming_without_coroutines"></a>The Problem: Asynchronous Programming Without Coroutines</h3>
<div class="paragraph">
<p>Consider a server application that handles network requests. The server must read a request, query a database, compute a response, and send it back. Each step might take time to complete.</p>
</div>
<div class="paragraph">
<p>In traditional synchronous code:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">void handle_request(connection&amp; conn)
{
std::string request = conn.read(); // blocks until data arrives
auto parsed = parse_request(request);
auto data = database.query(parsed.id); // blocks until database responds
auto response = compute_response(data);
conn.write(response); // blocks until write completes
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This code reads naturally from top to bottom. But while waiting for the network or database, this function blocks the entire thread. If you have thousands of concurrent connections, you would need thousands of threads, each consuming memory and requiring operating system scheduling.</p>
</div>
</div>
<div class="sect2">
<h3 id="_the_callback_approach"><a class="anchor" href="#_the_callback_approach"></a>The Callback Approach</h3>
<div class="paragraph">
<p>The traditional solution uses callbacks:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">void handle_request(connection&amp; conn)
{
conn.async_read([&amp;conn](std::string request) {
auto parsed = parse_request(request);
database.async_query(parsed.id, [&amp;conn](auto data) {
auto response = compute_response(data);
conn.async_write(response, [&amp;conn]() {
// request complete
});
});
});
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This code does not block. Each operation starts, registers a callback, and returns immediately. When the operation completes, the callback runs.</p>
</div>
<div class="paragraph">
<p>But look what has happened to the code: three levels of nesting, logic scattered across multiple lambda functions, and local variables that cannot be shared between callbacks without careful lifetime management. A single logical operation becomes fragmented across multiple functions.</p>
</div>
</div>
<div class="sect2">
<h3 id="_the_coroutine_solution"><a class="anchor" href="#_the_coroutine_solution"></a>The Coroutine Solution</h3>
<div class="paragraph">
<p>Coroutines restore linear code structure while maintaining asynchronous behavior:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;void&gt; handle_request(connection&amp; conn)
{
std::string request = co_await conn.async_read();
auto parsed = parse_request(request);
auto data = co_await database.async_query(parsed.id);
auto response = compute_response(data);
co_await conn.async_write(response);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This code reads like the original blocking version. Local variables like <code>request</code>, <code>parsed</code>, and <code>data</code> exist naturally in their scope. Yet the function suspends at each <code>co_await</code> point, allowing other work to proceed while waiting.</p>
</div>
</div>
<div class="sect2">
<h3 id="_beyond_asynchrony"><a class="anchor" href="#_beyond_asynchrony"></a>Beyond Asynchrony</h3>
<div class="paragraph">
<p>Coroutines also enable:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Generators</strong> — Functions that produce sequences of values on demand, computing each value only when requested</p>
</li>
<li>
<p><strong>State machines</strong> — Complex control flow expressed as linear code with suspension points</p>
</li>
<li>
<p><strong>Cooperative multitasking</strong> — Multiple logical tasks interleaved on a single thread</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>You have now learned what coroutines are and why they exist. In the next section, you will learn the C&#43;&#43;20 syntax for creating coroutines.</p>
</div>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/2.cpp20-coroutines/2a.foundations.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a></span>
<span class="next"><a href="2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,664 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Part II: C&#43;&#43;20 Syntax :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/2.cpp20-coroutines/2b.syntax.html">
<link rel="prev" href="2a.foundations.html">
<link rel="next" href="2c.machinery.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="2a.foundations.html">Part I: Foundations</a>
</li>
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../4.coroutines/4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a></li>
<li><a href="2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="2a.foundations.html">
<span class="material-symbols-outlined" title="Previous: Part I: Foundations">arrow_back</span>
</a>
<a accesskey="u" href="2.intro.html">
<span class="material-symbols-outlined" title="Up: Introduction To C&#43;&#43;20 Coroutines">arrow_upward</span>
</a>
<a accesskey="n" href="2c.machinery.html">
<span class="material-symbols-outlined" title="Next: Part III: Coroutine Machinery">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Part II: C&#43;&#43;20 Syntax</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section introduces the three C&#43;&#43;20 keywords that create coroutines and walks you through building your first coroutine step by step.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Completed <a href="2a.foundations.html" class="xref page">Part I: Foundations</a></p>
</li>
<li>
<p>Understanding of why coroutines exist and what problem they solve</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_three_keywords"><a class="anchor" href="#_the_three_keywords"></a>The Three Keywords</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A function becomes a coroutine when its body contains any of three special keywords: <code>co_await</code>, <code>co_yield</code>, or <code>co_return</code>. The presence of any of these keywords signals to the compiler that the function requires coroutine machinery.</p>
</div>
<div class="sect2">
<h3 id="_co_await"><a class="anchor" href="#_co_await"></a>co_await</h3>
<div class="paragraph">
<p>The <code>co_await</code> keyword suspends the coroutine and waits for some operation to complete. When you write <code>co_await expr</code>, the coroutine saves its state, pauses execution, and potentially allows other code to run. When the awaited operation completes, the coroutine resumes from exactly where it left off.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;std::string&gt; fetch_page(std::string url)
{
auto response = co_await http_get(url); // suspends until HTTP completes
return response.body; // continues after resumption
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_co_yield"><a class="anchor" href="#_co_yield"></a>co_yield</h3>
<div class="paragraph">
<p>The <code>co_yield</code> keyword produces a value and suspends the coroutine. This pattern creates <strong>generators</strong>—functions that produce sequences of values one at a time. After yielding a value, the coroutine pauses until someone asks for the next value.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">generator&lt;int&gt; count_to(int n)
{
for (int i = 1; i &lt;= n; ++i)
{
co_yield i; // produce value, suspend, resume when next value requested
}
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_co_return"><a class="anchor" href="#_co_return"></a>co_return</h3>
<div class="paragraph">
<p>The <code>co_return</code> keyword completes the coroutine and optionally provides a final result. Unlike a regular <code>return</code> statement, <code>co_return</code> interacts with the coroutine machinery to properly finalize the coroutine&#8217;s state.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;int&gt; compute()
{
int result = 42;
co_return result; // completes the coroutine with value 42
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>For coroutines that do not return a value, use <code>co_return;</code> without an argument.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_your_first_coroutine"><a class="anchor" href="#_your_first_coroutine"></a>Your First Coroutine</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The distinction between regular functions and coroutines matters because they behave fundamentally differently at runtime:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A regular function allocates its local variables on the stack. When it returns, those variables are gone.</p>
</li>
<li>
<p>A coroutine allocates its local variables in a heap-allocated <strong>coroutine frame</strong>. When it suspends, those variables persist. When it resumes, they are still there.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Here is the minimal structure needed to create a coroutine:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;coroutine&gt;
struct SimpleCoroutine
{
struct promise_type
{
SimpleCoroutine get_return_object() { return {}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
};
SimpleCoroutine my_first_coroutine()
{
co_return; // This makes it a coroutine
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>promise_type</code> nested structure provides the minimum scaffolding the compiler needs. You will learn what each method does in <a href="2c.machinery.html" class="xref page">Part III: Coroutine Machinery</a>.</p>
</div>
<div class="paragraph">
<p>For now, observe that the presence of <code>co_return</code> transforms what looks like a regular function into a coroutine. If you try to compile a function with coroutine keywords but without proper infrastructure, the compiler will produce errors.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_awaitables_and_awaiters"><a class="anchor" href="#_awaitables_and_awaiters"></a>Awaitables and Awaiters</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When you write <code>co_await expr</code>, the expression <code>expr</code> must be an <strong>awaitable</strong>—something that knows how to suspend and resume a coroutine. The awaitable produces an <strong>awaiter</strong> object that implements three methods:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>await_ready()</code> — Returns <code>true</code> if the result is immediately available and no suspension is needed</p>
</li>
<li>
<p><code>await_suspend(handle)</code> — Called when the coroutine suspends; receives a handle to the coroutine for later resumption</p>
</li>
<li>
<p><code>await_resume()</code> — Called when the coroutine resumes; its return value becomes the value of the <code>co_await</code> expression</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_example_understanding_the_awaiter_protocol"><a class="anchor" href="#_example_understanding_the_awaiter_protocol"></a>Example: Understanding the Awaiter Protocol</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;coroutine&gt;
#include &lt;iostream&gt;
struct ReturnObject
{
struct promise_type
{
ReturnObject get_return_object() { return {}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
};
struct Awaiter
{
std::coroutine_handle&lt;&gt;* handle_out;
bool await_ready() { return false; } // always suspend
void await_suspend(std::coroutine_handle&lt;&gt; h)
{
*handle_out = h; // store handle for later resumption
}
void await_resume() {} // nothing to return
};
ReturnObject counter(std::coroutine_handle&lt;&gt;* handle)
{
Awaiter awaiter{handle};
for (unsigned i = 0; ; ++i)
{
std::cout &lt;&lt; "counter: " &lt;&lt; i &lt;&lt; std::endl;
co_await awaiter;
}
}
int main()
{
std::coroutine_handle&lt;&gt; h;
counter(&amp;h);
for (int i = 0; i &lt; 3; ++i)
{
std::cout &lt;&lt; "main: resuming" &lt;&lt; std::endl;
h();
}
h.destroy();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Output:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-asciidoc hljs" data-lang="asciidoc">counter: 0
main: resuming
counter: 1
main: resuming
counter: 2
main: resuming
counter: 3</code></pre>
</div>
</div>
<div class="paragraph">
<p>Study this execution flow:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>main</code> calls <code>counter</code>, passing the address of a coroutine handle</p>
</li>
<li>
<p><code>counter</code> begins executing, prints "counter: 0", and reaches <code>co_await awaiter</code></p>
</li>
<li>
<p><code>await_ready()</code> returns <code>false</code>, so suspension proceeds</p>
</li>
<li>
<p><code>await_suspend</code> receives a handle to the suspended coroutine and stores it in <code>main&#8217;s variable `h</code></p>
</li>
<li>
<p>Control returns to <code>main</code>, which now holds a handle to the suspended coroutine</p>
</li>
<li>
<p><code>main</code> calls <code>h()</code>, which resumes the coroutine</p>
</li>
<li>
<p>The coroutine continues from where it left off, increments <code>i</code>, prints "counter: 1", and suspends again</p>
</li>
<li>
<p>This cycle repeats until <code>main</code> destroys the coroutine</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>The variable <code>i</code> inside <code>counter</code> maintains its value across all these suspension and resumption cycles.</p>
</div>
</div>
<div class="sect2">
<h3 id="_standard_awaiters"><a class="anchor" href="#_standard_awaiters"></a>Standard Awaiters</h3>
<div class="paragraph">
<p>The C&#43;&#43; standard library provides two predefined awaiters:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>std::suspend_always</code><code>await_ready()</code> returns <code>false</code> (always suspend)</p>
</li>
<li>
<p><code>std::suspend_never</code><code>await_ready()</code> returns <code>true</code> (never suspend)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>These are useful building blocks for promise types and custom awaitables.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">// suspend_always causes suspension at this point
co_await std::suspend_always{};
// suspend_never continues immediately without suspending
co_await std::suspend_never{};</code></pre>
</div>
</div>
<div class="paragraph">
<p>You have now learned the three coroutine keywords and how awaitables work. In the next section, you will learn about the promise type and coroutine handle—the machinery that makes coroutines function.</p>
</div>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/2.cpp20-coroutines/2b.syntax.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="2a.foundations.html">Part I: Foundations</a></span>
<span class="next"><a href="2c.machinery.html">Part III: Coroutine Machinery</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,840 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Part III: Coroutine Machinery :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/2.cpp20-coroutines/2c.machinery.html">
<link rel="prev" href="2b.syntax.html">
<link rel="next" href="2d.advanced.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../4.coroutines/4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a></li>
<li><a href="2c.machinery.html">Part III: Coroutine Machinery</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="2b.syntax.html">
<span class="material-symbols-outlined" title="Previous: Part II: C&#43;&#43;20 Syntax">arrow_back</span>
</a>
<a accesskey="u" href="2.intro.html">
<span class="material-symbols-outlined" title="Up: Introduction To C&#43;&#43;20 Coroutines">arrow_upward</span>
</a>
<a accesskey="n" href="2d.advanced.html">
<span class="material-symbols-outlined" title="Next: Part IV: Advanced Topics">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Part III: Coroutine Machinery</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section explains the promise type and coroutine handle—the core machinery that controls coroutine behavior. You will build a complete generator type by understanding how these pieces work together.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Completed <a href="2b.syntax.html" class="xref page">Part II: C&#43;&#43;20 Syntax</a></p>
</li>
<li>
<p>Understanding of the three coroutine keywords</p>
</li>
<li>
<p>Familiarity with awaitables and awaiters</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_promise_type"><a class="anchor" href="#_the_promise_type"></a>The Promise Type</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Every coroutine has an associated <strong>promise type</strong>. This type acts as a controller for the coroutine, defining how it behaves at key points in its lifecycle. The promise type is not something you pass to the coroutine—it is a nested type inside the coroutine&#8217;s return type that the compiler uses automatically.</p>
</div>
<div class="paragraph">
<p>The compiler expects to find a type named <code>promise_type</code> nested inside your coroutine&#8217;s return type. If your coroutine returns <code>Generator&lt;int&gt;</code>, the compiler looks for <code>Generator&lt;int&gt;::promise_type</code>.</p>
</div>
<div class="sect2">
<h3 id="_required_methods"><a class="anchor" href="#_required_methods"></a>Required Methods</h3>
<div class="paragraph">
<p>The promise type must provide these methods:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1"><code>get_return_object()</code></dt>
<dd>
<p>Called to create the object that will be returned to the caller of the coroutine. This happens before the coroutine body begins executing.</p>
</dd>
<dt class="hdlist1"><code>initial_suspend()</code></dt>
<dd>
<p>Called immediately after <code>get_return_object()</code>. Returns an awaiter that determines whether the coroutine should suspend before running any of its body. Return <code>std::suspend_never{}</code> to start executing immediately, or <code>std::suspend_always{}</code> to suspend before the first statement.</p>
</dd>
<dt class="hdlist1"><code>final_suspend()</code></dt>
<dd>
<p>Called when the coroutine completes (either normally or via exception). Returns an awaiter that determines whether to suspend one last time or destroy the coroutine state immediately. This method must be <code>noexcept</code>.</p>
</dd>
<dt class="hdlist1"><code>return_void()</code> or <code>return_value(v)</code></dt>
<dd>
<p>Called when the coroutine executes <code>co_return</code> or falls off the end of its body. Use <code>return_void()</code> if the coroutine does not return a value; use <code>return_value(v)</code> if it does. You must provide exactly one of these, matching how your coroutine returns.</p>
</dd>
<dt class="hdlist1"><code>unhandled_exception()</code></dt>
<dd>
<p>Called if an exception escapes the coroutine body. Typically you either rethrow the exception, store it for later, or terminate the program.</p>
</dd>
</dl>
</div>
</div>
<div class="sect2">
<h3 id="_the_compiler_transformation"><a class="anchor" href="#_the_compiler_transformation"></a>The Compiler Transformation</h3>
<div class="paragraph">
<p>The compiler transforms your coroutine body into something resembling this pseudocode:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">{
promise_type promise;
auto return_object = promise.get_return_object();
co_await promise.initial_suspend();
try {
// your coroutine body goes here
}
catch (...) {
promise.unhandled_exception();
}
co_await promise.final_suspend();
}
// coroutine frame is destroyed when control flows off the end</code></pre>
</div>
</div>
<div class="paragraph">
<p>Important observations:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The return object is created before <code>initial_suspend()</code> runs, so it is available even if the coroutine suspends immediately</p>
</li>
<li>
<p><code>final_suspend()</code> determines whether the coroutine frame persists after completion—if it returns <code>suspend_always</code>, you must manually destroy the coroutine; if it returns <code>suspend_never</code>, the frame is destroyed automatically</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_tracing_promise_behavior"><a class="anchor" href="#_tracing_promise_behavior"></a>Tracing Promise Behavior</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;coroutine&gt;
#include &lt;iostream&gt;
struct TracePromise
{
struct promise_type
{
promise_type()
{
std::cout &lt;&lt; "promise constructed" &lt;&lt; std::endl;
}
~promise_type()
{
std::cout &lt;&lt; "promise destroyed" &lt;&lt; std::endl;
}
TracePromise get_return_object()
{
std::cout &lt;&lt; "get_return_object called" &lt;&lt; std::endl;
return {};
}
std::suspend_never initial_suspend()
{
std::cout &lt;&lt; "initial_suspend called" &lt;&lt; std::endl;
return {};
}
std::suspend_always final_suspend() noexcept
{
std::cout &lt;&lt; "final_suspend called" &lt;&lt; std::endl;
return {};
}
void return_void()
{
std::cout &lt;&lt; "return_void called" &lt;&lt; std::endl;
}
void unhandled_exception()
{
std::cout &lt;&lt; "unhandled_exception called" &lt;&lt; std::endl;
}
};
};
TracePromise trace_coroutine()
{
std::cout &lt;&lt; "coroutine body begins" &lt;&lt; std::endl;
co_return;
}
int main()
{
std::cout &lt;&lt; "calling coroutine" &lt;&lt; std::endl;
auto result = trace_coroutine();
std::cout &lt;&lt; "coroutine returned" &lt;&lt; std::endl;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Output:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-asciidoc hljs" data-lang="asciidoc">calling coroutine
promise constructed
get_return_object called
initial_suspend called
coroutine body begins
return_void called
final_suspend called
coroutine returned</code></pre>
</div>
</div>
<div class="paragraph">
<p>Notice that the promise is constructed first, then <code>get_return_object()</code> creates the return value, then <code>initial_suspend()</code> runs. Since <code>initial_suspend()</code> returns <code>suspend_never</code>, the coroutine body executes immediately. After <code>co_return</code>, <code>return_void()</code> is called, followed by <code>final_suspend()</code>. Since <code>final_suspend()</code> returns <code>suspend_always</code>, the coroutine suspends one last time, and the promise is not destroyed until the coroutine handle is explicitly destroyed.</p>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
<div class="paragraph">
<p>If your coroutine can fall off the end of its body without executing <code>co_return</code>, and your promise type lacks a <code>return_void()</code> method, the behavior is undefined. Always ensure your promise type has <code>return_void()</code> if there is any code path that might reach the end of the coroutine body without an explicit <code>co_return</code>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_coroutine_handle"><a class="anchor" href="#_coroutine_handle"></a>Coroutine Handle</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A <code>std::coroutine_handle&lt;&gt;</code> is a lightweight object that refers to a suspended coroutine. It is similar to a pointer: it does not own the memory it references, and copying it does not copy the coroutine.</p>
</div>
<div class="sect2">
<h3 id="_basic_operations"><a class="anchor" href="#_basic_operations"></a>Basic Operations</h3>
<div class="ulist">
<ul>
<li>
<p><code>handle()</code> or <code>handle.resume()</code> — Resume the coroutine</p>
</li>
<li>
<p><code>handle.done()</code> — Returns <code>true</code> if the coroutine has completed</p>
</li>
<li>
<p><code>handle.destroy()</code> — Destroy the coroutine frame (frees memory)</p>
</li>
<li>
<p><code>handle.promise()</code> — Returns a reference to the promise object (typed handles only)</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_typed_vs_untyped_handles"><a class="anchor" href="#_typed_vs_untyped_handles"></a>Typed vs Untyped Handles</h3>
<div class="dlist">
<dl>
<dt class="hdlist1"><code>std::coroutine_handle&lt;&gt;</code></dt>
<dd>
<p>The most basic form (equivalent to <code>std::coroutine_handle&lt;void&gt;</code>). Can reference any coroutine but provides no access to the promise object.</p>
</dd>
<dt class="hdlist1"><code>std::coroutine_handle&lt;PromiseType&gt;</code></dt>
<dd>
<p>A typed handle that knows about a particular promise type. Can be converted to the void handle. Provides a <code>promise()</code> method that returns a reference to the promise object.</p>
</dd>
</dl>
</div>
</div>
<div class="sect2">
<h3 id="_creating_handles_from_promises"><a class="anchor" href="#_creating_handles_from_promises"></a>Creating Handles from Promises</h3>
<div class="paragraph">
<p>Inside <code>get_return_object()</code>, you can obtain the coroutine handle using:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::coroutine_handle&lt;promise_type&gt;::from_promise(*this)</code></pre>
</div>
</div>
<div class="paragraph">
<p>Since <code>get_return_object()</code> is called on the promise object (as <code>this</code>), this method returns a handle to the coroutine containing that promise.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_putting_it_together_building_a_generator"><a class="anchor" href="#_putting_it_together_building_a_generator"></a>Putting It Together: Building a Generator</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A <strong>generator</strong> is a function that produces a sequence of values on demand. Instead of computing all values upfront, a generator computes each value when requested using <code>co_yield</code>.</p>
</div>
<div class="sect2">
<h3 id="_how_co_yield_works"><a class="anchor" href="#_how_co_yield_works"></a>How co_yield Works</h3>
<div class="paragraph">
<p>The expression <code>co_yield value</code> is transformed by the compiler into:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">co_await promise.yield_value(value)</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>yield_value</code> method receives the yielded value, stores it somewhere accessible, and returns an awaiter (usually <code>std::suspend_always</code>) to suspend the coroutine.</p>
</div>
</div>
<div class="sect2">
<h3 id="_complete_generator_implementation"><a class="anchor" href="#_complete_generator_implementation"></a>Complete Generator Implementation</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;coroutine&gt;
#include &lt;iostream&gt;
struct Generator
{
struct promise_type
{
int current_value;
Generator get_return_object()
{
return Generator{
std::coroutine_handle&lt;promise_type&gt;::from_promise(*this)
};
}
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
std::suspend_always yield_value(int value)
{
current_value = value;
return {};
}
void return_void() {}
void unhandled_exception() { std::terminate(); }
};
std::coroutine_handle&lt;promise_type&gt; handle;
Generator(std::coroutine_handle&lt;promise_type&gt; h) : handle(h) {}
~Generator()
{
if (handle)
handle.destroy();
}
// Disable copying
Generator(Generator const&amp;) = delete;
Generator&amp; operator=(Generator const&amp;) = delete;
// Enable moving
Generator(Generator&amp;&amp; other) noexcept
: handle(other.handle)
{
other.handle = nullptr;
}
Generator&amp; operator=(Generator&amp;&amp; other) noexcept
{
if (this != &amp;other)
{
if (handle)
handle.destroy();
handle = other.handle;
other.handle = nullptr;
}
return *this;
}
bool next()
{
if (!handle || handle.done())
return false;
handle.resume();
return !handle.done();
}
int value() const
{
return handle.promise().current_value;
}
};
Generator count_to(int n)
{
for (int i = 1; i &lt;= n; ++i)
{
co_yield i;
}
}
int main()
{
auto gen = count_to(5);
while (gen.next())
{
std::cout &lt;&lt; gen.value() &lt;&lt; std::endl;
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Output:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-asciidoc hljs" data-lang="asciidoc">1
2
3
4
5</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_key_design_decisions"><a class="anchor" href="#_key_design_decisions"></a>Key Design Decisions</h3>
<div class="dlist">
<dl>
<dt class="hdlist1"><code>initial_suspend()</code> returns <code>suspend_always</code></dt>
<dd>
<p>The coroutine suspends before running any user code. This means the first call to <code>next()</code> starts the coroutine running.</p>
</dd>
<dt class="hdlist1"><code>final_suspend()</code> returns <code>suspend_always</code></dt>
<dd>
<p>The coroutine frame persists after completion. This is necessary because the iterator needs to check <code>handle.done()</code> after the last value.</p>
</dd>
<dt class="hdlist1">Generator owns the handle</dt>
<dd>
<p>The destructor calls <code>handle.destroy()</code> to free the coroutine frame. Copying is disabled to avoid double-free; moving transfers ownership.</p>
</dd>
<dt class="hdlist1"><code>yield_value</code> stores and suspends</dt>
<dd>
<p>Stores the yielded value in <code>current_value</code> and returns <code>suspend_always</code> to pause the coroutine after each yield.</p>
</dd>
</dl>
</div>
</div>
<div class="sect2">
<h3 id="_fibonacci_generator"><a class="anchor" href="#_fibonacci_generator"></a>Fibonacci Generator</h3>
<div class="paragraph">
<p>Here is a more interesting generator that produces the Fibonacci sequence:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">Generator fibonacci()
{
int a = 0, b = 1;
while (true)
{
co_yield a;
int next = a + b;
a = b;
b = next;
}
}
int main()
{
auto fib = fibonacci();
for (int i = 0; i &lt; 10 &amp;&amp; fib.next(); ++i)
{
std::cout &lt;&lt; fib.value() &lt;&lt; " ";
}
std::cout &lt;&lt; std::endl;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Output:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-asciidoc hljs" data-lang="asciidoc">0 1 1 2 3 5 8 13 21 34</code></pre>
</div>
</div>
<div class="paragraph">
<p>The Fibonacci generator runs an infinite loop internally. It will produce values forever. But because it yields and suspends after each value, the caller controls when (and whether) to ask for more values. The generator only computes values on demand.</p>
</div>
<div class="paragraph">
<p>The variables <code>a</code> and <code>b</code> persist across yields because they live in the coroutine frame on the heap.</p>
</div>
<div class="paragraph">
<p>You have now learned how promise types and coroutine handles work together to create useful abstractions like generators. In the next section, you will explore advanced topics: symmetric transfer, allocation, and exception handling.</p>
</div>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/2.cpp20-coroutines/2c.machinery.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a></span>
<span class="next"><a href="2d.advanced.html">Part IV: Advanced Topics</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,999 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Part IV: Advanced Topics :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/2.cpp20-coroutines/2d.advanced.html">
<link rel="prev" href="2c.machinery.html">
<link rel="next" href="../3.concurrency/3.intro.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../4.coroutines/4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a></li>
<li><a href="2d.advanced.html">Part IV: Advanced Topics</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="2c.machinery.html">
<span class="material-symbols-outlined" title="Previous: Part III: Coroutine Machinery">arrow_back</span>
</a>
<a accesskey="u" href="2.intro.html">
<span class="material-symbols-outlined" title="Up: Introduction To C&#43;&#43;20 Coroutines">arrow_upward</span>
</a>
<a accesskey="n" href="../3.concurrency/3.intro.html">
<span class="material-symbols-outlined" title="Next: Introduction to Concurrency">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Part IV: Advanced Topics</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section covers advanced coroutine topics: symmetric transfer for efficient resumption, coroutine allocation strategies, and exception handling. These concepts are essential for building production-quality coroutine types.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Completed <a href="2c.machinery.html" class="xref page">Part III: Coroutine Machinery</a></p>
</li>
<li>
<p>Understanding of promise types, coroutine handles, and generators</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_symmetric_transfer"><a class="anchor" href="#_symmetric_transfer"></a>Symmetric Transfer</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When a coroutine completes or awaits another coroutine, control must transfer somewhere. The naive approach—simply calling <code>handle.resume()</code>—has a problem: each nested coroutine adds a frame to the call stack. With deep nesting, you risk stack overflow.</p>
</div>
<div class="paragraph">
<p><strong>Symmetric transfer</strong> solves this by returning a coroutine handle from <code>await_suspend</code>. Instead of resuming the target coroutine via a function call, the compiler generates a tail call that transfers control without growing the stack.</p>
</div>
<div class="sect2">
<h3 id="_the_problem_stack_accumulation"><a class="anchor" href="#_the_problem_stack_accumulation"></a>The Problem: Stack Accumulation</h3>
<div class="paragraph">
<p>Consider a chain of coroutines where each awaits the next:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;&gt; a() { co_await b(); }
task&lt;&gt; b() { co_await c(); }
task&lt;&gt; c() { co_return; }</code></pre>
</div>
</div>
<div class="paragraph">
<p>Without symmetric transfer, when <code>a</code> awaits <code>b</code>:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>a</code> calls into the awaiter&#8217;s <code>await_suspend</code></p>
</li>
<li>
<p><code>await_suspend</code> calls <code>b.handle.resume()</code></p>
</li>
<li>
<p><code>b</code> runs, calls into its awaiter&#8217;s <code>await_suspend</code></p>
</li>
<li>
<p>That calls <code>c.handle.resume()</code></p>
</li>
<li>
<p>The stack now has frames for `a&#8217;s suspension, `b&#8217;s suspension, and `c&#8217;s execution</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>Each suspension adds a stack frame. With thousands of nested coroutines, the stack overflows.</p>
</div>
</div>
<div class="sect2">
<h3 id="_the_solution_return_the_handle"><a class="anchor" href="#_the_solution_return_the_handle"></a>The Solution: Return the Handle</h3>
<div class="paragraph">
<p><code>await_suspend</code> can return a <code>std::coroutine_handle&lt;&gt;</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::coroutine_handle&lt;&gt; await_suspend(std::coroutine_handle&lt;&gt; h)
{
// store continuation for later
continuation_ = h;
// return handle to resume (instead of calling resume())
return next_coroutine_;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>When <code>await_suspend</code> returns a handle, the compiler generates code equivalent to:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">auto next = awaiter.await_suspend(current);
if (next != std::noop_coroutine())
next.resume(); // tail call, doesn't grow stack</code></pre>
</div>
</div>
<div class="paragraph">
<p>The key insight: returning a handle enables the compiler to implement the resumption as a tail call. The current stack frame is reused for the next coroutine.</p>
</div>
</div>
<div class="sect2">
<h3 id="_return_types_for_await_suspend"><a class="anchor" href="#_return_types_for_await_suspend"></a>Return Types for await_suspend</h3>
<div class="paragraph">
<p><code>await_suspend</code> can return three types:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1"><code>void</code></dt>
<dd>
<p>Always suspend. The coroutine is suspended and some external mechanism must resume it.</p>
</dd>
<dt class="hdlist1"><code>bool</code></dt>
<dd>
<p>Conditional suspension. Return <code>true</code> to suspend, <code>false</code> to continue without suspending.</p>
</dd>
<dt class="hdlist1"><code>std::coroutine_handle&lt;&gt;</code></dt>
<dd>
<p>Symmetric transfer. The returned handle is resumed; returning <code>std::noop_coroutine()</code> suspends without resuming anything.</p>
</dd>
</dl>
</div>
</div>
<div class="sect2">
<h3 id="_using_symmetric_transfer_in_generators"><a class="anchor" href="#_using_symmetric_transfer_in_generators"></a>Using Symmetric Transfer in Generators</h3>
<div class="paragraph">
<p>A production generator uses symmetric transfer at <code>final_suspend</code> to return to whoever is iterating:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">auto final_suspend() noexcept
{
struct awaiter
{
promise_type* p_;
bool await_ready() const noexcept { return false; }
std::coroutine_handle&lt;&gt; await_suspend(std::coroutine_handle&lt;&gt;) noexcept
{
// Return to the consumer that called resume()
return p_-&gt;consumer_handle_;
}
void await_resume() const noexcept {}
};
return awaiter{this};
}</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_coroutine_allocation"><a class="anchor" href="#_coroutine_allocation"></a>Coroutine Allocation</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Every coroutine needs memory for its <strong>coroutine frame</strong>—the heap-allocated structure holding local variables, parameters, and suspension state.</p>
</div>
<div class="sect2">
<h3 id="_default_allocation"><a class="anchor" href="#_default_allocation"></a>Default Allocation</h3>
<div class="paragraph">
<p>By default, coroutines allocate their frames using <code>operator new</code>. The frame size depends on:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Local variables in the coroutine</p>
</li>
<li>
<p>Parameters (copied into the frame)</p>
</li>
<li>
<p>Promise type members</p>
</li>
<li>
<p>Compiler-generated bookkeeping</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_heap_allocation_elision_optimization_halo"><a class="anchor" href="#_heap_allocation_elision_optimization_halo"></a>Heap Allocation eLision Optimization (HALO)</h3>
<div class="paragraph">
<p>Compilers can sometimes eliminate coroutine frame allocation entirely through <strong>HALO</strong> (Heap Allocation eLision Optimization). When the compiler can prove that:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The coroutine&#8217;s lifetime is contained within the caller&#8217;s lifetime</p>
</li>
<li>
<p>The frame size is known at compile time</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>&#8230;&#8203;it may allocate the frame on the caller&#8217;s stack instead of the heap.</p>
</div>
<div class="paragraph">
<p>HALO is most effective when:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Coroutines are awaited immediately after creation</p>
</li>
<li>
<p>The coroutine type is marked with <code><a id="clang::coro_await_elidable"></a></code> (Clang extension)</p>
</li>
<li>
<p>Optimization is enabled (<code>-O2</code> or higher)</p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">// HALO might apply here because the task is awaited immediately
co_await compute_something();
// HALO cannot apply here because the task escapes
auto task = compute_something();
store_for_later(std::move(task));</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_custom_allocators"><a class="anchor" href="#_custom_allocators"></a>Custom Allocators</h3>
<div class="paragraph">
<p>Promise types can customize allocation by providing <code>operator new</code> and <code>operator delete</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">struct promise_type
{
// Custom allocation
static void* operator new(std::size_t size)
{
return my_allocator.allocate(size);
}
static void operator delete(void* ptr, std::size_t size)
{
my_allocator.deallocate(ptr, size);
}
// ... rest of promise type
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>The promise&#8217;s <code>operator new</code> receives only the frame size. To access allocator arguments passed to the coroutine, use the leading allocator convention with <code>std::allocator_arg_t</code> as the first parameter.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_exception_handling"><a class="anchor" href="#_exception_handling"></a>Exception Handling</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Exceptions in coroutines require special handling because a coroutine can suspend and resume across different call stacks.</p>
</div>
<div class="sect2">
<h3 id="_the_exception_flow"><a class="anchor" href="#_the_exception_flow"></a>The Exception Flow</h3>
<div class="paragraph">
<p>When an exception is thrown inside a coroutine and not caught:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>The exception is caught by an implicit try-catch surrounding the coroutine body</p>
</li>
<li>
<p><code>promise.unhandled_exception()</code> is called while the exception is active</p>
</li>
<li>
<p>After <code>unhandled_exception()</code> returns, <code>co_await promise.final_suspend()</code> executes</p>
</li>
<li>
<p>The coroutine completes (suspended or destroyed, depending on <code>final_suspend</code>)</p>
</li>
</ol>
</div>
</div>
<div class="sect2">
<h3 id="_options_in_unhandled_exception"><a class="anchor" href="#_options_in_unhandled_exception"></a>Options in unhandled_exception()</h3>
<div class="paragraph">
<p><strong>Terminate the program:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">void unhandled_exception()
{
std::terminate();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Store for later retrieval:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">void unhandled_exception()
{
exception_ = std::current_exception();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Rethrow immediately:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">void unhandled_exception()
{
throw; // propagates to whoever resumed the coroutine
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Swallow the exception:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">void unhandled_exception()
{
// silently ignored - almost always a mistake
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_the_store_and_rethrow_pattern"><a class="anchor" href="#_the_store_and_rethrow_pattern"></a>The Store-and-Rethrow Pattern</h3>
<div class="paragraph">
<p>For tasks and generators where callers expect results, store the exception and rethrow it when results are requested:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">struct promise_type
{
std::exception_ptr exception_;
void unhandled_exception()
{
exception_ = std::current_exception();
}
};
// In the return object's result accessor:
T get_result()
{
if (handle_.promise().exception_)
std::rethrow_exception(handle_.promise().exception_);
return std::move(handle_.promise().result_);
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_exception_example"><a class="anchor" href="#_exception_example"></a>Exception Example</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;coroutine&gt;
#include &lt;exception&gt;
#include &lt;iostream&gt;
#include &lt;stdexcept&gt;
struct Task
{
struct promise_type
{
std::exception_ptr exception;
Task get_return_object()
{
return Task{std::coroutine_handle&lt;promise_type&gt;::from_promise(*this)};
}
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception()
{
exception = std::current_exception();
}
};
std::coroutine_handle&lt;promise_type&gt; handle;
Task(std::coroutine_handle&lt;promise_type&gt; h) : handle(h) {}
~Task() { if (handle) handle.destroy(); }
void run() { handle.resume(); }
void check_exception()
{
if (handle.promise().exception)
std::rethrow_exception(handle.promise().exception);
}
};
Task risky_operation()
{
std::cout &lt;&lt; "Starting risky operation" &lt;&lt; std::endl;
throw std::runtime_error("Something went wrong");
co_return; // never reached
}
int main()
{
Task task = risky_operation();
try
{
task.run();
task.check_exception();
std::cout &lt;&lt; "Operation completed successfully" &lt;&lt; std::endl;
}
catch (std::exception const&amp; e)
{
std::cout &lt;&lt; "Operation failed: " &lt;&lt; e.what() &lt;&lt; std::endl;
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Output:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-asciidoc hljs" data-lang="asciidoc">Starting risky operation
Operation failed: Something went wrong</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_initialization_exceptions"><a class="anchor" href="#_initialization_exceptions"></a>Initialization Exceptions</h3>
<div class="paragraph">
<p>Exceptions thrown before the first suspension point (before <code>initial_suspend</code> completes) propagate directly to the caller without going through <code>unhandled_exception()</code>. If <code>initial_suspend()</code> returns <code>suspend_always</code>, the coroutine suspends before any user code runs, avoiding this edge case.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_building_a_production_generator"><a class="anchor" href="#_building_a_production_generator"></a>Building a Production Generator</h2>
<div class="sectionbody">
<div class="paragraph">
<p>With all these concepts, here is a production-quality generic generator:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;coroutine&gt;
#include &lt;exception&gt;
#include &lt;utility&gt;
template&lt;typename T&gt;
class Generator
{
public:
struct promise_type
{
T value_;
std::exception_ptr exception_;
Generator get_return_object()
{
return Generator{Handle::from_promise(*this)};
}
std::suspend_always initial_suspend() noexcept { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
std::suspend_always yield_value(T v)
{
value_ = std::move(v);
return {};
}
void return_void() noexcept {}
void unhandled_exception()
{
exception_ = std::current_exception();
}
// Prevent co_await inside generators
template&lt;typename U&gt;
std::suspend_never await_transform(U&amp;&amp;) = delete;
};
using Handle = std::coroutine_handle&lt;promise_type&gt;;
class iterator
{
Handle handle_;
public:
using iterator_category = std::input_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
iterator() : handle_(nullptr) {}
explicit iterator(Handle h) : handle_(h) {}
iterator&amp; operator++()
{
handle_.resume();
if (handle_.done())
{
auto&amp; promise = handle_.promise();
handle_ = nullptr;
if (promise.exception_)
std::rethrow_exception(promise.exception_);
}
return *this;
}
T&amp; operator*() const { return handle_.promise().value_; }
bool operator==(iterator const&amp; other) const
{
return handle_ == other.handle_;
}
};
iterator begin()
{
if (handle_)
{
handle_.resume();
if (handle_.done())
{
auto&amp; promise = handle_.promise();
if (promise.exception_)
std::rethrow_exception(promise.exception_);
return iterator{};
}
}
return iterator{handle_};
}
iterator end() { return iterator{}; }
~Generator() { if (handle_) handle_.destroy(); }
Generator(Generator const&amp;) = delete;
Generator&amp; operator=(Generator const&amp;) = delete;
Generator(Generator&amp;&amp; other) noexcept
: handle_(std::exchange(other.handle_, nullptr)) {}
Generator&amp; operator=(Generator&amp;&amp; other) noexcept
{
if (this != &amp;other)
{
if (handle_) handle_.destroy();
handle_ = std::exchange(other.handle_, nullptr);
}
return *this;
}
private:
Handle handle_;
explicit Generator(Handle h) : handle_(h) {}
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>This generator:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Provides a standard iterator interface for range-based for loops</p>
</li>
<li>
<p>Stores and rethrows exceptions during iteration</p>
</li>
<li>
<p>Prevents <code>co_await</code> inside generators via deleted <code>await_transform</code></p>
</li>
<li>
<p>Manages coroutine lifetime with RAII</p>
</li>
<li>
<p>Supports move semantics</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_conclusion"><a class="anchor" href="#_conclusion"></a>Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
<p>You have now learned the complete mechanics of C&#43;&#43;20 coroutines:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Keywords</strong><code>co_await</code>, <code>co_yield</code>, and <code>co_return</code> transform functions into coroutines</p>
</li>
<li>
<p><strong>Promise types</strong> — Control coroutine behavior at initialization, suspension, completion, and error handling</p>
</li>
<li>
<p><strong>Coroutine handles</strong> — Lightweight references for resuming, querying, and destroying coroutines</p>
</li>
<li>
<p><strong>Symmetric transfer</strong> — Efficient control flow without stack accumulation</p>
</li>
<li>
<p><strong>Allocation</strong> — Custom allocation and HALO optimization</p>
</li>
<li>
<p><strong>Exception handling</strong> — Capturing and propagating exceptions across suspension points</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>These fundamentals prepare you for understanding Capy&#8217;s <code>task&lt;T&gt;</code> type and the IoAwaitable protocol, which build on standard coroutine machinery with executor affinity and stop token propagation.</p>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/2.cpp20-coroutines/2d.advanced.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="2c.machinery.html">Part III: Coroutine Machinery</a></span>
<span class="next"><a href="../3.concurrency/3.intro.html">Introduction to Concurrency</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,386 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Introduction to Concurrency :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/3.concurrency/3.intro.html">
<link rel="prev" href="../2.cpp20-coroutines/2d.advanced.html">
<link rel="next" href="3a.foundations.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class=" is-current-page" data-depth="1">
<a class="nav-link" href="3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../4.coroutines/4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="3.intro.html">Introduction to Concurrency</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="../2.cpp20-coroutines/2d.advanced.html">
<span class="material-symbols-outlined" title="Previous: Part IV: Advanced Topics">arrow_back</span>
</a>
<a class="disabled" accesskey="u" aria-disabled="true" tabindex="-1">
<span class="material-symbols-outlined" title="Up:">arrow_upward</span>
</a>
<a accesskey="n" href="3a.foundations.html">
<span class="material-symbols-outlined" title="Next: Part I: Foundations">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Introduction to Concurrency</h1>
<div class="paragraph">
<p>Your processor has multiple cores. Your operating system runs hundreds of threads. Your users expect responsive interfaces while your server handles thousands of simultaneous connections. Concurrency is not an advanced topic reserved for specialists&#8212;&#8203;it is the reality of modern software.</p>
</div>
<div class="paragraph">
<p>Yet concurrent programming has a reputation for being treacherous, and that reputation is earned. Two threads reading and writing the same variable can produce results that are impossible to reproduce, impossible to debug, and impossible to reason about by staring at the code. A program that passes every test can still corrupt data in production under load. The bugs are real, and they are subtle.</p>
</div>
<div class="paragraph">
<p>The good news: these problems are well understood. Decades of research and practice have produced clear patterns, precise vocabulary, and reliable tools. Once you understand the fundamentals&#8212;&#8203;what a data race actually is, why memory ordering matters, how synchronization primitives work&#8212;&#8203;concurrent code becomes something you can reason about with confidence.</p>
</div>
<div class="paragraph">
<p>This section builds your understanding of concurrency from first principles. No prior experience with threads or parallel programming is needed. You will learn what makes concurrent code hard to reason about, how the standard synchronization tools work, and the architectural patterns that tame that complexity. When you finish, you will have the vocabulary and mental models to understand how Capy&#8217;s coroutine-based concurrency works under the hood&#8212;&#8203;and why it eliminates entire categories of the bugs described here.</p>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/3.concurrency/3.intro.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a></span>
<span class="next"><a href="3a.foundations.html">Part I: Foundations</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,678 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Part I: Foundations :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/3.concurrency/3a.foundations.html">
<link rel="prev" href="3.intro.html">
<link rel="next" href="3b.synchronization.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../4.coroutines/4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="3.intro.html">Introduction to Concurrency</a></li>
<li><a href="3a.foundations.html">Part I: Foundations</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="3.intro.html">
<span class="material-symbols-outlined" title="Previous: Introduction to Concurrency">arrow_back</span>
</a>
<a accesskey="u" href="3.intro.html">
<span class="material-symbols-outlined" title="Up: Introduction to Concurrency">arrow_upward</span>
</a>
<a accesskey="n" href="3b.synchronization.html">
<span class="material-symbols-outlined" title="Next: Part II: Synchronization">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Part I: Foundations</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section introduces the fundamental concepts of concurrent programming. You will learn what concurrency is, why it matters, and how threads provide the foundation for parallel execution.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Before beginning this tutorial, you should have:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A C&#43;&#43; compiler with C&#43;&#43;11 or later support</p>
</li>
<li>
<p>Familiarity with basic C&#43;&#43; concepts: functions, classes, and lambdas</p>
</li>
<li>
<p>Understanding of how programs execute sequentially</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_why_concurrency_matters"><a class="anchor" href="#_why_concurrency_matters"></a>Why Concurrency Matters</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Modern computers have multiple processor cores. A quad-core laptop can do four things at once. But most programs use only one core, leaving the others idle. Concurrency lets you use all your processing power.</p>
</div>
<div class="paragraph">
<p>Consider downloading a large file. Without concurrency, your application freezes—the user interface becomes unresponsive because your single thread of execution is busy waiting for network data. With concurrency, one thread handles the download while another keeps the interface responsive. The user can continue working, cancel the download, or start another—all while data streams in.</p>
</div>
<div class="paragraph">
<p>The benefits compound in computationally intensive work. Image processing, scientific simulations, video encoding—these tasks can be split into independent pieces. Process them simultaneously and your program finishes in a fraction of the time.</p>
</div>
<div class="paragraph">
<p>But concurrency is not free. It introduces complexity. Multiple threads accessing the same data can corrupt it. Threads waiting on each other can freeze forever. These problems—<strong>race conditions</strong> and <strong>deadlocks</strong>—are the challenges you will learn to handle.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_threadsyour_programs_parallel_lives"><a class="anchor" href="#_threadsyour_programs_parallel_lives"></a>Threads—Your Program&#8217;s Parallel Lives</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When you run a program, the operating system creates a <strong>process</strong> for it. This process gets its own memory space, its own resources, and at least one <strong>thread of execution</strong>—the main thread.</p>
</div>
<div class="paragraph">
<p>Think of a thread as a bookmark in a book of instructions. It marks where you are in the code. The processor reads the instruction at that bookmark, executes it, and moves the bookmark forward. One thread means one bookmark—your program can only be at one place in the code at a time.</p>
</div>
<div class="paragraph">
<p>But you can create additional threads. Each thread is its own bookmark, tracking its own position in the code. Now your program can be at multiple places simultaneously. Each thread has its own <strong>call stack</strong>—its own record of which functions called which—but all threads share the same <strong>heap memory</strong>.</p>
</div>
<div class="paragraph">
<p>This sharing is both the power and the peril of threads.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_creating_threads"><a class="anchor" href="#_creating_threads"></a>Creating Threads</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <code>&lt;thread&gt;</code> header provides <code>std::thread</code>, the standard way to create threads in C&#43;&#43;.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;thread&gt;
void say_hello()
{
std::cout &lt;&lt; "Hello from a new thread!\n";
}
int main()
{
std::thread t(say_hello);
t.join();
std::cout &lt;&lt; "Back in the main thread.\n";
return 0;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>std::thread</code> constructor takes a function (or any <strong>callable</strong>) and immediately starts a new thread running that function. Two bookmarks now move through your code simultaneously.</p>
</div>
<div class="paragraph">
<p>The <code>join()</code> call makes the main thread wait until thread <code>t</code> finishes. Without it, <code>main()</code> might return and terminate the program before <code>say_hello()</code> completes. Always join your threads before they go out of scope.</p>
</div>
<div class="sect2">
<h3 id="_parallel_execution"><a class="anchor" href="#_parallel_execution"></a>Parallel Execution</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;thread&gt;
void count_up(char const* name)
{
for (int i = 1; i &lt;= 5; ++i)
std::cout &lt;&lt; name &lt;&lt; ": " &lt;&lt; i &lt;&lt; "\n";
}
int main()
{
std::thread alice(count_up, "Alice");
std::thread bob(count_up, "Bob");
alice.join();
bob.join();
return 0;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Run this and you might see output like:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-asciidoc hljs" data-lang="asciidoc">Alice: 1
Bob: 1
Alice: 2
Bob: 2
Alice: 3
...</code></pre>
</div>
</div>
<div class="paragraph">
<p>Or perhaps:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-asciidoc hljs" data-lang="asciidoc">AliceBob: : 1
1
Alice: 2
...</code></pre>
</div>
</div>
<div class="paragraph">
<p>The interleaving varies each run. Both threads race to print, and their outputs jumble together. This unpredictability is your first glimpse of concurrent programming&#8217;s fundamental challenge: when threads share resources (here, <code>std::cout</code>), chaos can ensue.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_ways_to_create_threads"><a class="anchor" href="#_ways_to_create_threads"></a>Ways to Create Threads</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Threads accept any callable object: functions, lambda expressions, function objects (functors), and member functions.</p>
</div>
<div class="sect2">
<h3 id="_lambda_expressions"><a class="anchor" href="#_lambda_expressions"></a>Lambda Expressions</h3>
<div class="paragraph">
<p>Lambda expressions are often the clearest choice:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;thread&gt;
int main()
{
int x = 42;
std::thread t([x]() {
std::cout &lt;&lt; "The value is: " &lt;&lt; x &lt;&lt; "\n";
});
t.join();
return 0;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The lambda captures <code>x</code> by value—it copies <code>x</code> into the lambda. By default, <code>std::thread</code> copies all arguments passed to it. Even if your function declares a reference parameter, the thread receives a copy.</p>
</div>
<div class="paragraph">
<p>To pass by reference, use <code>std::ref()</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;thread&gt;
void increment(int&amp; value)
{
++value;
}
int main()
{
int counter = 0;
std::thread t(increment, std::ref(counter));
t.join();
std::cout &lt;&lt; "Counter is now: " &lt;&lt; counter &lt;&lt; "\n";
return 0;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Without <code>std::ref()</code>, the thread would modify a copy, leaving <code>counter</code> unchanged.</p>
</div>
</div>
<div class="sect2">
<h3 id="_member_functions"><a class="anchor" href="#_member_functions"></a>Member Functions</h3>
<div class="paragraph">
<p>For member functions, pass a pointer to the function and an instance:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;thread&gt;
#include &lt;string&gt;
class Greeter
{
public:
void greet(std::string const&amp; name)
{
std::cout &lt;&lt; "Hello, " &lt;&lt; name &lt;&lt; "!\n";
}
};
int main()
{
Greeter g;
std::thread t(&amp;Greeter::greet, &amp;g, "World");
t.join();
return 0;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>&amp;Greeter::greet</code> syntax names the member function; <code>&amp;g</code> provides the instance to call it on.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_thread_lifecycle_join_detach_and_destruction"><a class="anchor" href="#_thread_lifecycle_join_detach_and_destruction"></a>Thread Lifecycle: Join, Detach, and Destruction</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Every thread must be either <strong>joined</strong> or <strong>detached</strong> before its <code>std::thread</code> object is destroyed. Failing to do so calls <code>std::terminate()</code>, abruptly ending your program.</p>
</div>
<div class="sect2">
<h3 id="_join"><a class="anchor" href="#_join"></a>join()</h3>
<div class="paragraph">
<p><code>join()</code> blocks the calling thread until the target thread finishes. This is how you wait for work to complete:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::thread t(do_work);
// ... do other things ...
t.join(); // wait for do_work to finish</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_detach"><a class="anchor" href="#_detach"></a>detach()</h3>
<div class="paragraph">
<p>Sometimes you want a thread to run independently, continuing even after the <code>std::thread</code> object is destroyed. That is what <code>detach()</code> does:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::thread t(background_task);
t.detach(); // thread runs independently
// t is now "empty"—no longer associated with a thread</code></pre>
</div>
</div>
<div class="paragraph">
<p>A detached thread becomes a <strong>daemon thread</strong>. It runs until it finishes or the program exits. You lose all ability to wait for it or check its status. Use detachment sparingly—usually for fire-and-forget background work.</p>
</div>
</div>
<div class="sect2">
<h3 id="_checking_joinable"><a class="anchor" href="#_checking_joinable"></a>Checking joinable()</h3>
<div class="paragraph">
<p>Before joining or detaching, you can check if a thread is <strong>joinable</strong>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::thread t(some_function);
if (t.joinable())
{
t.join();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>A thread is joinable if it represents an actual thread of execution. After joining or detaching, or after default construction, a <code>std::thread</code> is not joinable.</p>
</div>
<div class="paragraph">
<p>You have now learned the basics of threads: creation, execution, and lifecycle management. In the next section, you will learn about the dangers of shared data and how to protect it with synchronization primitives.</p>
</div>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/3.concurrency/3a.foundations.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="3.intro.html">Introduction to Concurrency</a></span>
<span class="next"><a href="3b.synchronization.html">Part II: Synchronization</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,650 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Part II: Synchronization :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/3.concurrency/3b.synchronization.html">
<link rel="prev" href="3a.foundations.html">
<link rel="next" href="3c.advanced.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="3a.foundations.html">Part I: Foundations</a>
</li>
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../4.coroutines/4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="3.intro.html">Introduction to Concurrency</a></li>
<li><a href="3b.synchronization.html">Part II: Synchronization</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="3a.foundations.html">
<span class="material-symbols-outlined" title="Previous: Part I: Foundations">arrow_back</span>
</a>
<a accesskey="u" href="3.intro.html">
<span class="material-symbols-outlined" title="Up: Introduction to Concurrency">arrow_upward</span>
</a>
<a accesskey="n" href="3c.advanced.html">
<span class="material-symbols-outlined" title="Next: Part III: Advanced Primitives">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Part II: Synchronization</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section introduces the dangers of shared data access and the synchronization primitives that protect against them. You will learn about race conditions, mutexes, lock guards, and deadlocks.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Completed <a href="3a.foundations.html" class="xref page">Part I: Foundations</a></p>
</li>
<li>
<p>Understanding of threads and their lifecycle</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_danger_race_conditions"><a class="anchor" href="#_the_danger_race_conditions"></a>The Danger: Race Conditions</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When multiple threads read the same data, all is well. But when at least one thread writes while others read or write, you have a <strong>data race</strong>. The result is undefined behavior—crashes, corruption, or silent errors.</p>
</div>
<div class="paragraph">
<p>Consider this code:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;thread&gt;
int counter = 0;
void increment_many_times()
{
for (int i = 0; i &lt; 100000; ++i)
++counter;
}
int main()
{
std::thread t1(increment_many_times);
std::thread t2(increment_many_times);
t1.join();
t2.join();
std::cout &lt;&lt; "Counter: " &lt;&lt; counter &lt;&lt; "\n";
return 0;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Two threads, each incrementing 100,000 times. You would expect 200,000. But run this repeatedly and you will see different results—180,000, 195,327, maybe occasionally 200,000. Something is wrong.</p>
</div>
<div class="paragraph">
<p>The <code>++counter</code> operation looks atomic—indivisible—but it is not. It actually consists of three steps:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Read the current value</p>
</li>
<li>
<p>Add one</p>
</li>
<li>
<p>Write the result back</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>Between any of these steps, the other thread might execute its own steps. Imagine both threads read <code>counter</code> when it is 5. Both add one, getting 6. Both write 6 back. Two increments, but the counter only went up by one. This is a <strong>lost update</strong>, a classic race condition.</p>
</div>
<div class="paragraph">
<p>The more threads, the more opportunity for races. The faster your processor, the more instructions execute between context switches, potentially hiding the bug—until one critical day in production.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_mutual_exclusion_mutexes"><a class="anchor" href="#_mutual_exclusion_mutexes"></a>Mutual Exclusion: Mutexes</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The solution to data races is <strong>mutual exclusion</strong>: ensuring that only one thread accesses shared data at a time.</p>
</div>
<div class="paragraph">
<p>A <strong>mutex</strong> (mutual exclusion object) is a lockable resource. Before accessing shared data, a thread <strong>locks</strong> the mutex. If another thread already holds the lock, the requesting thread blocks until the lock is released. This serializes access to the protected data.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;thread&gt;
#include &lt;mutex&gt;
int counter = 0;
std::mutex counter_mutex;
void increment_many_times()
{
for (int i = 0; i &lt; 100000; ++i)
{
counter_mutex.lock();
++counter;
counter_mutex.unlock();
}
}
int main()
{
std::thread t1(increment_many_times);
std::thread t2(increment_many_times);
t1.join();
t2.join();
std::cout &lt;&lt; "Counter: " &lt;&lt; counter &lt;&lt; "\n";
return 0;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Now the output is always 200,000. The mutex ensures that between <code>lock()</code> and <code>unlock()</code>, only one thread executes. The increment is now effectively atomic.</p>
</div>
<div class="paragraph">
<p>But there is a problem with calling <code>lock()</code> and <code>unlock()</code> directly. If code between them throws an exception, <code>unlock()</code> never executes. The mutex stays locked forever, and any thread waiting for it blocks eternally—a <strong>deadlock</strong>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_lock_guards_safety_through_raii"><a class="anchor" href="#_lock_guards_safety_through_raii"></a>Lock Guards: Safety Through RAII</h2>
<div class="sectionbody">
<div class="paragraph">
<p>C&#43;&#43; has a powerful idiom: <strong>RAII</strong> (Resource Acquisition Is Initialization). The idea: acquire resources in a constructor, release them in the destructor. Since destructors run even when exceptions are thrown, cleanup is guaranteed.</p>
</div>
<div class="paragraph">
<p>Lock guards apply RAII to mutexes:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;thread&gt;
#include &lt;mutex&gt;
int counter = 0;
std::mutex counter_mutex;
void increment_many_times()
{
for (int i = 0; i &lt; 100000; ++i)
{
std::lock_guard&lt;std::mutex&gt; lock(counter_mutex);
++counter;
// lock is automatically released when it goes out of scope
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>std::lock_guard</code> locks the mutex on construction and unlocks it on destruction. Even if an exception is thrown, the destructor runs and the mutex is released. This is the correct way to use mutexes.</p>
</div>
<div class="sect2">
<h3 id="_stdscoped_lock_c17"><a class="anchor" href="#_stdscoped_lock_c17"></a>std::scoped_lock (C&#43;&#43;17)</h3>
<div class="paragraph">
<p>Since C&#43;&#43;17, <code>std::scoped_lock</code> is preferred. It works like <code>lock_guard</code> but can lock multiple mutexes simultaneously, avoiding a class of deadlock:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::scoped_lock lock(counter_mutex); // C++17</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_stdunique_lock"><a class="anchor" href="#_stdunique_lock"></a>std::unique_lock</h3>
<div class="paragraph">
<p>For more control, use <code>std::unique_lock</code>. It can be unlocked before destruction, moved to another scope, or created without immediately locking:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::unique_lock&lt;std::mutex&gt; lock(some_mutex, std::defer_lock);
// mutex not yet locked
lock.lock(); // lock when ready
// ... do work ...
lock.unlock(); // unlock early if needed
// ... do other work ...
// destructor unlocks again if still locked</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>std::unique_lock</code> is more flexible but slightly more expensive than <code>std::lock_guard</code>. Use the simplest tool that does the job.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_deadlock_dragon"><a class="anchor" href="#_the_deadlock_dragon"></a>The Deadlock Dragon</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Mutexes solve data races but introduce a new danger: <strong>deadlock</strong>.</p>
</div>
<div class="paragraph">
<p>Imagine two threads and two mutexes. Thread A locks mutex 1, then tries to lock mutex 2. Thread B locks mutex 2, then tries to lock mutex 1. Each thread holds one mutex and waits for the other. Neither can proceed. The program freezes.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::mutex mutex1, mutex2;
void thread_a()
{
std::lock_guard&lt;std::mutex&gt; lock1(mutex1);
std::lock_guard&lt;std::mutex&gt; lock2(mutex2); // blocks, waiting for B
// ...
}
void thread_b()
{
std::lock_guard&lt;std::mutex&gt; lock2(mutex2);
std::lock_guard&lt;std::mutex&gt; lock1(mutex1); // blocks, waiting for A
// ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>If both threads run and each acquires its first mutex before the other acquires the second, deadlock occurs.</p>
</div>
<div class="sect2">
<h3 id="_preventing_deadlock"><a class="anchor" href="#_preventing_deadlock"></a>Preventing Deadlock</h3>
<div class="paragraph">
<p>The simplest prevention: <strong>always lock mutexes in the same order</strong>. If every thread locks <code>mutex1</code> before <code>mutex2</code>, no cycle can form.</p>
</div>
<div class="paragraph">
<p>When you need to lock multiple mutexes and cannot guarantee order, use <code>std::scoped_lock</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">void safe_function()
{
std::scoped_lock lock(mutex1, mutex2); // locks both atomically
// ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>std::scoped_lock</code> uses a deadlock-avoidance algorithm internally, acquiring both mutexes without risk of circular waiting.</p>
</div>
</div>
<div class="sect2">
<h3 id="_deadlock_prevention_rules"><a class="anchor" href="#_deadlock_prevention_rules"></a>Deadlock Prevention Rules</h3>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><strong>Lock in consistent order</strong> — Define a global ordering for mutexes and always lock in that order</p>
</li>
<li>
<p><strong>Use std::scoped_lock for multiple mutexes</strong> — Let the library handle deadlock avoidance</p>
</li>
<li>
<p><strong>Hold locks for minimal time</strong> — Reduce the window for contention</p>
</li>
<li>
<p><strong>Avoid nested locks when possible</strong> — Simpler designs prevent deadlock by construction</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>You have now learned about race conditions, mutexes, lock guards, and deadlocks. In the next section, you will explore advanced synchronization primitives: atomics, condition variables, and shared locks.</p>
</div>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/3.concurrency/3b.synchronization.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="3a.foundations.html">Part I: Foundations</a></span>
<span class="next"><a href="3c.advanced.html">Part III: Advanced Primitives</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,697 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Part III: Advanced Primitives :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/3.concurrency/3c.advanced.html">
<link rel="prev" href="3b.synchronization.html">
<link rel="next" href="3d.patterns.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../4.coroutines/4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="3.intro.html">Introduction to Concurrency</a></li>
<li><a href="3c.advanced.html">Part III: Advanced Primitives</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="3b.synchronization.html">
<span class="material-symbols-outlined" title="Previous: Part II: Synchronization">arrow_back</span>
</a>
<a accesskey="u" href="3.intro.html">
<span class="material-symbols-outlined" title="Up: Introduction to Concurrency">arrow_upward</span>
</a>
<a accesskey="n" href="3d.patterns.html">
<span class="material-symbols-outlined" title="Next: Part IV: Communication &amp; Patterns">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Part III: Advanced Primitives</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section covers advanced synchronization primitives: atomics for lock-free operations, condition variables for efficient waiting, and shared locks for reader/writer patterns.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Completed <a href="3b.synchronization.html" class="xref page">Part II: Synchronization</a></p>
</li>
<li>
<p>Understanding of mutexes, lock guards, and deadlocks</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_atomics_lock_free_operations"><a class="anchor" href="#_atomics_lock_free_operations"></a>Atomics: Lock-Free Operations</h2>
<div class="sectionbody">
<div class="paragraph">
<p>For operations on individual values, mutexes might be overkill. <strong>Atomic types</strong> provide lock-free thread safety for single variables.</p>
</div>
<div class="paragraph">
<p>An atomic operation completes entirely before any other thread can observe its effects. There is no intermediate state.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;thread&gt;
#include &lt;atomic&gt;
std::atomic&lt;int&gt; counter{0};
void increment_many_times()
{
for (int i = 0; i &lt; 100000; ++i)
++counter; // atomic increment
}
int main()
{
std::thread t1(increment_many_times);
std::thread t2(increment_many_times);
t1.join();
t2.join();
std::cout &lt;&lt; "Counter: " &lt;&lt; counter &lt;&lt; "\n";
return 0;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>No mutex, no lock guard, yet the result is always 200,000. The <code>std::atomic&lt;int&gt;</code> ensures that increments are indivisible.</p>
</div>
<div class="sect2">
<h3 id="_when_to_use_atomics"><a class="anchor" href="#_when_to_use_atomics"></a>When to Use Atomics</h3>
<div class="paragraph">
<p>Atomics work best for single-variable operations: counters, flags, simple state. They are faster than mutexes when contention is low. But they cannot protect complex operations involving multiple variables—for that, you need mutexes.</p>
</div>
<div class="paragraph">
<p>Common atomic types include:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>std::atomic&lt;bool&gt;</code> — Thread-safe boolean flag</p>
</li>
<li>
<p><code>std::atomic&lt;int&gt;</code> — Thread-safe integer counter</p>
</li>
<li>
<p><code>std::atomic&lt;T*&gt;</code> — Thread-safe pointer</p>
</li>
<li>
<p><code>std::atomic&lt;std::shared_ptr&lt;T&gt;&gt;</code> — Thread-safe shared pointer (C&#43;&#43;20)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Any trivially copyable type can be made atomic.</p>
</div>
</div>
<div class="sect2">
<h3 id="_atomic_operations"><a class="anchor" href="#_atomic_operations"></a>Atomic Operations</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::atomic&lt;int&gt; value{0};
value.store(42); // atomic write
int x = value.load(); // atomic read
int old = value.exchange(10); // atomic read-modify-write
value.fetch_add(5); // atomic addition, returns old value
value.fetch_sub(3); // atomic subtraction, returns old value
// Compare-and-swap (CAS)
int expected = 10;
bool success = value.compare_exchange_strong(expected, 20);
// If value == expected, sets value = 20 and returns true
// Otherwise, sets expected = value and returns false</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_condition_variables_efficient_waiting"><a class="anchor" href="#_condition_variables_efficient_waiting"></a>Condition Variables: Efficient Waiting</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Sometimes a thread must wait for a specific condition before proceeding. You could loop, repeatedly checking:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">// Inefficient busy-wait
while (!ready)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This works but wastes CPU cycles and introduces latency. <strong>Condition variables</strong> provide efficient waiting.</p>
</div>
<div class="paragraph">
<p>A condition variable allows one thread to signal others that something has changed. Waiting threads sleep until notified, consuming no CPU.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;thread&gt;
#include &lt;mutex&gt;
#include &lt;condition_variable&gt;
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker()
{
std::unique_lock&lt;std::mutex&gt; lock(mtx);
cv.wait(lock, []{ return ready; }); // wait until ready is true
std::cout &lt;&lt; "Worker proceeding!\n";
}
void signal_ready()
{
{
std::lock_guard&lt;std::mutex&gt; lock(mtx);
ready = true;
}
cv.notify_one(); // wake one waiting thread
}
int main()
{
std::thread t(worker);
std::this_thread::sleep_for(std::chrono::seconds(1));
signal_ready();
t.join();
return 0;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The worker thread calls <code>cv.wait()</code>, which atomically releases the mutex and suspends the thread. When <code>signal_ready()</code> calls <code>notify_one()</code>, the worker wakes up, reacquires the mutex, checks the condition, and proceeds.</p>
</div>
<div class="sect2">
<h3 id="_the_predicate"><a class="anchor" href="#_the_predicate"></a>The Predicate</h3>
<div class="paragraph">
<p>The lambda <code>[]{ return ready; }</code> is the <strong>predicate</strong>. <code>wait()</code> will not return until this evaluates to true. This guards against <strong>spurious wakeups</strong>—rare events where a thread wakes without notification. Always use a predicate.</p>
</div>
</div>
<div class="sect2">
<h3 id="_notification_methods"><a class="anchor" href="#_notification_methods"></a>Notification Methods</h3>
<div class="ulist">
<ul>
<li>
<p><code>notify_one()</code> — Wake a single waiting thread</p>
</li>
<li>
<p><code>notify_all()</code> — Wake all waiting threads</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Use <code>notify_one()</code> when only one thread needs to proceed (e.g., producer-consumer with single consumer). Use <code>notify_all()</code> when multiple threads might need to check the condition (e.g., broadcast events, shutdown signals).</p>
</div>
</div>
<div class="sect2">
<h3 id="_wait_variants"><a class="anchor" href="#_wait_variants"></a>Wait Variants</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">// Wait indefinitely
cv.wait(lock, predicate);
// Wait with timeout
auto status = cv.wait_for(lock, std::chrono::seconds(5), predicate);
// Returns true if predicate is true, false on timeout
// Wait until specific time point
auto status = cv.wait_until(lock, deadline, predicate);</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_shared_locks_readers_and_writers"><a class="anchor" href="#_shared_locks_readers_and_writers"></a>Shared Locks: Readers and Writers</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Consider a data structure that is read frequently but written rarely. A regular mutex serializes all access—but why block readers from each other? Multiple threads can safely read simultaneously; only writes require exclusive access.</p>
</div>
<div class="paragraph">
<p><strong>Shared mutexes</strong> support this pattern:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;thread&gt;
#include &lt;shared_mutex&gt;
#include &lt;vector&gt;
std::shared_mutex rw_mutex;
std::vector&lt;int&gt; data;
void reader(int id)
{
std::shared_lock&lt;std::shared_mutex&gt; lock(rw_mutex); // shared access
std::cout &lt;&lt; "Reader " &lt;&lt; id &lt;&lt; " sees " &lt;&lt; data.size() &lt;&lt; " elements\n";
}
void writer(int value)
{
std::unique_lock&lt;std::shared_mutex&gt; lock(rw_mutex); // exclusive access
data.push_back(value);
std::cout &lt;&lt; "Writer added " &lt;&lt; value &lt;&lt; "\n";
}</code></pre>
</div>
</div>
<div class="sect2">
<h3 id="_lock_types"><a class="anchor" href="#_lock_types"></a>Lock Types</h3>
<div class="dlist">
<dl>
<dt class="hdlist1"><code>std::shared_lock</code></dt>
<dd>
<p>Acquires a <strong>shared lock</strong>—multiple threads can hold shared locks simultaneously.</p>
</dd>
<dt class="hdlist1"><code>std::unique_lock</code> (on shared_mutex)</dt>
<dd>
<p>Acquires an <strong>exclusive lock</strong>—no other locks (shared or exclusive) can be held.</p>
</dd>
</dl>
</div>
</div>
<div class="sect2">
<h3 id="_behavior"><a class="anchor" href="#_behavior"></a>Behavior</h3>
<div class="ulist">
<ul>
<li>
<p>While any reader holds a shared lock, writers must wait</p>
</li>
<li>
<p>While a writer holds an exclusive lock, everyone waits</p>
</li>
<li>
<p>Multiple readers can proceed simultaneously</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This pattern maximizes concurrency for read-heavy workloads. Use <code>std::shared_mutex</code> when reads vastly outnumber writes.</p>
</div>
</div>
<div class="sect2">
<h3 id="_example_thread_safe_cache"><a class="anchor" href="#_example_thread_safe_cache"></a>Example: Thread-Safe Cache</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;shared_mutex&gt;
#include &lt;unordered_map&gt;
#include &lt;string&gt;
#include &lt;optional&gt;
class ThreadSafeCache
{
std::unordered_map&lt;std::string, std::string&gt; cache_;
mutable std::shared_mutex mutex_;
public:
std::optional&lt;std::string&gt; get(std::string const&amp; key) const
{
std::shared_lock lock(mutex_); // readers can proceed in parallel
auto it = cache_.find(key);
if (it != cache_.end())
return it-&gt;second;
return std::nullopt;
}
void put(std::string const&amp; key, std::string const&amp; value)
{
std::unique_lock lock(mutex_); // exclusive access for writing
cache_[key] = value;
}
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>Multiple threads can call <code>get()</code> simultaneously without blocking each other. Only <code>put()</code> requires exclusive access.</p>
</div>
<div class="paragraph">
<p>You have now learned about atomics, condition variables, and shared locks. In the next section, you will explore communication patterns: futures, promises, async, and practical concurrent patterns.</p>
</div>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/3.concurrency/3c.advanced.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="3b.synchronization.html">Part II: Synchronization</a></span>
<span class="next"><a href="3d.patterns.html">Part IV: Communication &amp; Patterns</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,766 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Part IV: Communication &amp; Patterns :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/3.concurrency/3d.patterns.html">
<link rel="prev" href="3c.advanced.html">
<link rel="next" href="../4.coroutines/4.intro.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../4.coroutines/4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="3.intro.html">Introduction to Concurrency</a></li>
<li><a href="3d.patterns.html">Part IV: Communication &amp; Patterns</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="3c.advanced.html">
<span class="material-symbols-outlined" title="Previous: Part III: Advanced Primitives">arrow_back</span>
</a>
<a accesskey="u" href="3.intro.html">
<span class="material-symbols-outlined" title="Up: Introduction to Concurrency">arrow_upward</span>
</a>
<a accesskey="n" href="../4.coroutines/4.intro.html">
<span class="material-symbols-outlined" title="Next: Coroutines in Capy">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Part IV: Communication &amp; Patterns</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section covers communication mechanisms for getting results from threads and practical patterns for concurrent programming.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Completed <a href="3c.advanced.html" class="xref page">Part III: Advanced Primitives</a></p>
</li>
<li>
<p>Understanding of atomics, condition variables, and shared locks</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_futures_and_promises_getting_results_back"><a class="anchor" href="#_futures_and_promises_getting_results_back"></a>Futures and Promises: Getting Results Back</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Threads can perform work, but how do you get results from them? Passing references works but is clunky. C&#43;&#43; offers a cleaner abstraction: <strong>futures</strong> and <strong>promises</strong>.</p>
</div>
<div class="paragraph">
<p>A <code>std::promise</code> is a write-once container: a thread can set its value. A <code>std::future</code> is the corresponding read-once container: another thread can get that value. They form a one-way communication channel.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;thread&gt;
#include &lt;future&gt;
void compute(std::promise&lt;int&gt; result_promise)
{
int answer = 6 * 7; // expensive computation
result_promise.set_value(answer);
}
int main()
{
std::promise&lt;int&gt; promise;
std::future&lt;int&gt; future = promise.get_future();
std::thread t(compute, std::move(promise));
std::cout &lt;&lt; "Waiting for result...\n";
int result = future.get(); // blocks until value is set
std::cout &lt;&lt; "The answer is: " &lt;&lt; result &lt;&lt; "\n";
t.join();
return 0;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The worker thread calls <code>set_value()</code>. The main thread calls <code>get()</code>, which blocks until the value is available.</p>
</div>
<div class="sect2">
<h3 id="_important_behaviors"><a class="anchor" href="#_important_behaviors"></a>Important Behaviors</h3>
<div class="ulist">
<ul>
<li>
<p>A future&#8217;s <code>get()</code> can only be called once</p>
</li>
<li>
<p>For multiple consumers, use <code>std::shared_future</code></p>
</li>
<li>
<p>If the promise is destroyed without setting a value, <code>get()</code> throws <code>std::future_error</code></p>
</li>
<li>
<p><code>set_exception()</code> allows the worker to signal an error</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_stdasync_the_easy_path"><a class="anchor" href="#_stdasync_the_easy_path"></a>std::async: The Easy Path</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Creating threads manually, managing promises, joining at the end—it is mechanical. <code>std::async</code> automates it:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;future&gt;
int compute()
{
return 6 * 7;
}
int main()
{
std::future&lt;int&gt; future = std::async(compute);
std::cout &lt;&lt; "Computing...\n";
int result = future.get();
std::cout &lt;&lt; "Result: " &lt;&lt; result &lt;&lt; "\n";
return 0;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>std::async</code> launches the function (potentially in a new thread), returning a future. No explicit thread creation, no promise management, no join call.</p>
</div>
<div class="sect2">
<h3 id="_launch_policies"><a class="anchor" href="#_launch_policies"></a>Launch Policies</h3>
<div class="paragraph">
<p>By default, the system decides whether to run the function in a new thread or defer it until you call <code>get()</code>. You can specify:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">// Force a new thread
auto future = std::async(std::launch::async, compute);
// Defer execution until get()
auto future = std::async(std::launch::deferred, compute);
// Let the system decide (default)
auto future = std::async(std::launch::async | std::launch::deferred, compute);</code></pre>
</div>
</div>
<div class="paragraph">
<p>For quick parallel tasks, <code>std::async</code> is often the cleanest choice.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_thread_local_storage"><a class="anchor" href="#_thread_local_storage"></a>Thread-Local Storage</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Sometimes each thread needs its own copy of a variable—not shared, not copied each call, but persistent within that thread.</p>
</div>
<div class="paragraph">
<p>Declare it <code>thread_local</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;thread&gt;
thread_local int counter = 0;
void increment_and_print(char const* name)
{
++counter;
std::cout &lt;&lt; name &lt;&lt; " counter: " &lt;&lt; counter &lt;&lt; "\n";
}
int main()
{
std::thread t1([]{
increment_and_print("T1");
increment_and_print("T1");
});
std::thread t2([]{
increment_and_print("T2");
increment_and_print("T2");
});
t1.join();
t2.join();
return 0;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Each thread sees its own <code>counter</code>. T1 prints 1, then 2. T2 independently prints 1, then 2. No synchronization needed because the data is not shared.</p>
</div>
<div class="paragraph">
<p>Thread-local storage is useful for per-thread caches, random number generators, or error state.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_practical_patterns"><a class="anchor" href="#_practical_patterns"></a>Practical Patterns</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_producer_consumer_queue"><a class="anchor" href="#_producer_consumer_queue"></a>Producer-Consumer Queue</h3>
<div class="paragraph">
<p>One or more threads produce work items; one or more threads consume them. A queue connects them:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;thread&gt;
#include &lt;mutex&gt;
#include &lt;condition_variable&gt;
#include &lt;queue&gt;
template&lt;typename T&gt;
class ThreadSafeQueue
{
std::queue&lt;T&gt; queue_;
std::mutex mutex_;
std::condition_variable cv_;
public:
void push(T value)
{
{
std::lock_guard&lt;std::mutex&gt; lock(mutex_);
queue_.push(std::move(value));
}
cv_.notify_one();
}
T pop()
{
std::unique_lock&lt;std::mutex&gt; lock(mutex_);
cv_.wait(lock, [this]{ return !queue_.empty(); });
T value = std::move(queue_.front());
queue_.pop();
return value;
}
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>The producer pushes items; the consumer waits for items and processes them. The condition variable ensures the consumer sleeps efficiently when the queue is empty.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">ThreadSafeQueue&lt;int&gt; work_queue;
void producer()
{
for (int i = 0; i &lt; 10; ++i)
{
work_queue.push(i);
std::cout &lt;&lt; "Produced: " &lt;&lt; i &lt;&lt; "\n";
}
}
void consumer()
{
for (int i = 0; i &lt; 10; ++i)
{
int item = work_queue.pop();
std::cout &lt;&lt; "Consumed: " &lt;&lt; item &lt;&lt; "\n";
}
}
int main()
{
std::thread prod(producer);
std::thread cons(consumer);
prod.join();
cons.join();
return 0;
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_parallel_for"><a class="anchor" href="#_parallel_for"></a>Parallel For</h3>
<div class="paragraph">
<p>Split a loop across multiple threads:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;iostream&gt;
#include &lt;thread&gt;
#include &lt;vector&gt;
#include &lt;functional&gt;
void parallel_for(int start, int end, int num_threads,
std::function&lt;void(int)&gt; func)
{
std::vector&lt;std::thread&gt; threads;
int chunk_size = (end - start) / num_threads;
for (int t = 0; t &lt; num_threads; ++t)
{
int chunk_start = start + t * chunk_size;
int chunk_end = (t == num_threads - 1) ? end : chunk_start + chunk_size;
threads.emplace_back([=]{
for (int i = chunk_start; i &lt; chunk_end; ++i)
func(i);
});
}
for (auto&amp; thread : threads)
thread.join();
}
int main()
{
std::mutex print_mutex;
parallel_for(0, 20, 4, [&amp;](int i){
std::lock_guard&lt;std::mutex&gt; lock(print_mutex);
std::cout &lt;&lt; "Processing " &lt;&lt; i &lt;&lt; " on thread "
&lt;&lt; std::this_thread::get_id() &lt;&lt; "\n";
});
return 0;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The work is divided into chunks, each handled by its own thread. For CPU-bound work on large datasets, this can dramatically reduce execution time.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_summary"><a class="anchor" href="#_summary"></a>Summary</h2>
<div class="sectionbody">
<div class="paragraph">
<p>You have learned the fundamentals of concurrent programming:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Threads</strong> — Independent flows of execution within a process</p>
</li>
<li>
<p><strong>Mutexes</strong> — Mutual exclusion to prevent data races</p>
</li>
<li>
<p><strong>Lock guards</strong> — RAII wrappers that ensure mutexes are properly released</p>
</li>
<li>
<p><strong>Atomics</strong> — Lock-free safety for single operations</p>
</li>
<li>
<p><strong>Condition variables</strong> — Efficient waiting for events</p>
</li>
<li>
<p><strong>Shared locks</strong> — Multiple readers or one writer</p>
</li>
<li>
<p><strong>Futures and promises</strong> — Communication of results between threads</p>
</li>
<li>
<p><strong>std::async</strong> — Simplified launching of parallel work</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>You have seen the dangers—race conditions, deadlocks—and the tools to avoid them.</p>
</div>
<div class="sect2">
<h3 id="_best_practices"><a class="anchor" href="#_best_practices"></a>Best Practices</h3>
<div class="ulist">
<ul>
<li>
<p><strong>Start with std::async</strong> when possible</p>
</li>
<li>
<p><strong>Prefer immutable data</strong> — shared data that never changes needs no synchronization</p>
</li>
<li>
<p><strong>Protect mutable shared state carefully</strong> — minimize the data that is shared</p>
</li>
<li>
<p><strong>Minimize lock duration</strong> — hold locks for as brief a time as possible</p>
</li>
<li>
<p><strong>Avoid nested locks</strong> — when unavoidable, use <code>std::scoped_lock</code></p>
</li>
<li>
<p><strong>Test thoroughly</strong> — test with many threads, on different machines, under load</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Concurrency is challenging. Bugs hide until the worst moment. Testing is hard because timing varies. But the rewards are substantial: responsive applications, full hardware utilization, and elegant solutions to naturally parallel problems.</p>
</div>
<div class="paragraph">
<p>This foundation prepares you for understanding Capy&#8217;s concurrency facilities: <code>thread_pool</code>, <code>strand</code>, <code>when_all</code>, and <code>async_event</code>. These build on standard primitives to provide coroutine-friendly concurrent programming.</p>
</div>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/3.concurrency/3d.patterns.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="3c.advanced.html">Part III: Advanced Primitives</a></span>
<span class="next"><a href="../4.coroutines/4.intro.html">Coroutines in Capy</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,386 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Coroutines in Capy :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/4.coroutines/4.intro.html">
<link rel="prev" href="../3.concurrency/3d.patterns.html">
<link rel="next" href="4a.tasks.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class=" is-current-page" data-depth="1">
<a class="nav-link" href="4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="4.intro.html">Coroutines in Capy</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="../3.concurrency/3d.patterns.html">
<span class="material-symbols-outlined" title="Previous: Part IV: Communication &amp; Patterns">arrow_back</span>
</a>
<a class="disabled" accesskey="u" aria-disabled="true" tabindex="-1">
<span class="material-symbols-outlined" title="Up:">arrow_upward</span>
</a>
<a accesskey="n" href="4a.tasks.html">
<span class="material-symbols-outlined" title="Next: The task Type">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Coroutines in Capy</h1>
<div class="paragraph">
<p>You know how C&#43;&#43;20 coroutines work at the language level. You understand threads, synchronization, and the problems that concurrency introduces. Now it is time to see how Capy brings these together into a practical, high-performance library.</p>
</div>
<div class="paragraph">
<p>Capy&#8217;s coroutine model is built around a single principle: asynchronous code should look like synchronous code. You write a function that reads from a socket, processes the data, and writes a response&#8212;&#8203;top to bottom, with local variables and normal control flow. Capy handles suspension, resumption, thread scheduling, and cancellation behind the scenes. The result is code that is both easier to read and harder to get wrong.</p>
</div>
<div class="paragraph">
<p>But this is not magic, and it is not a black box. Every piece of Capy&#8217;s coroutine infrastructure is designed to be transparent. You can see how tasks are scheduled, control where they run, propagate cancellation, compose concurrent operations, and tune memory allocation. Understanding these mechanisms is what separates someone who uses the library from someone who uses it <em>well</em>.</p>
</div>
<div class="paragraph">
<p>This section is the bridge between theory and practice. You will see how Capy turns C++20 coroutines into a complete async programming model&#8212;&#8203;from launching and scheduling tasks, through cancellation and concurrent composition, to fine-grained control over memory allocation. Each topic builds on the last, and by the end you will be writing real asynchronous programs with Capy.</p>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/4.coroutines/4.intro.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a></span>
<span class="next"><a href="4a.tasks.html">The task Type</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,687 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>The task Type :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/4.coroutines/4a.tasks.html">
<link rel="prev" href="4.intro.html">
<link rel="next" href="4b.launching.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="4.intro.html">Coroutines in Capy</a></li>
<li><a href="4a.tasks.html">The task Type</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="4.intro.html">
<span class="material-symbols-outlined" title="Previous: Coroutines in Capy">arrow_back</span>
</a>
<a accesskey="u" href="4.intro.html">
<span class="material-symbols-outlined" title="Up: Coroutines in Capy">arrow_upward</span>
</a>
<a accesskey="n" href="4b.launching.html">
<span class="material-symbols-outlined" title="Next: Launching Coroutines">arrow_forward</span>
</a>
</div></div>
<h1 class="page">The task Type</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section introduces Capy&#8217;s <code>task&lt;T&gt;</code> type—the fundamental coroutine type for asynchronous programming in Capy.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Completed <a href="../2.cpp20-coroutines/2d.advanced.html" class="xref page">C&#43;&#43;20 Coroutines Tutorial</a></p>
</li>
<li>
<p>Understanding of promise types, coroutine handles, and symmetric transfer</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_overview"><a class="anchor" href="#_overview"></a>Overview</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>task&lt;T&gt;</code> is Capy&#8217;s primary coroutine return type. It represents an asynchronous operation that eventually produces a value of type <code>T</code> (or nothing, for <code>task&lt;void&gt;</code>).</p>
</div>
<div class="paragraph">
<p>Key characteristics:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Lazy execution</strong> — The coroutine does not start until awaited</p>
</li>
<li>
<p><strong>Symmetric transfer</strong> — Efficient resumption without stack accumulation</p>
</li>
<li>
<p><strong>Executor inheritance</strong> — Inherits the caller&#8217;s executor unless explicitly bound</p>
</li>
<li>
<p><strong>Stop token propagation</strong> — Forward-propagates cancellation signals</p>
</li>
<li>
<p><strong>HALO support</strong> — Enables heap allocation elision when possible</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_declaring_task_coroutines"><a class="anchor" href="#_declaring_task_coroutines"></a>Declaring task Coroutines</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Any function that returns <code>task&lt;T&gt;</code> and contains coroutine keywords (<code>co_await</code>, <code>co_return</code>) is a <code>task</code> coroutine:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;boost/capy.hpp&gt;
using namespace boost::capy;
task&lt;int&gt; compute_value()
{
co_return 42;
}
task&lt;std::string&gt; fetch_greeting()
{
co_return "Hello, Capy!";
}
task&lt;&gt; do_nothing() // task&lt;void&gt;
{
co_return;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The syntax <code>task&lt;&gt;</code> is equivalent to <code>task&lt;void&gt;</code> and represents a coroutine that completes without producing a value.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_returning_values_with_co_return"><a class="anchor" href="#_returning_values_with_co_return"></a>Returning Values with co_return</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Use <code>co_return</code> to complete the coroutine and provide its result:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;int&gt; add(int a, int b)
{
int result = a + b;
co_return result; // Completes with value
}
task&lt;&gt; log_message(std::string msg)
{
std::cout &lt;&lt; msg &lt;&lt; "\n";
co_return; // Completes without value
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>For <code>task&lt;void&gt;</code>, you can either use <code>co_return;</code> explicitly or let execution fall off the end of the function body.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_awaiting_other_tasks"><a class="anchor" href="#_awaiting_other_tasks"></a>Awaiting Other Tasks</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Tasks can await other tasks using <code>co_await</code>. This is the primary mechanism for composing asynchronous operations:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;int&gt; step_one()
{
co_return 10;
}
task&lt;int&gt; step_two(int x)
{
co_return x * 2;
}
task&lt;int&gt; full_operation()
{
int a = co_await step_one(); // Suspends until step_one completes
int b = co_await step_two(a); // Suspends until step_two completes
co_return b + 5; // Final result: 25
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>When you <code>co_await</code> a task:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>The current coroutine suspends</p>
</li>
<li>
<p>The awaited task starts executing</p>
</li>
<li>
<p>When the awaited task completes, the current coroutine resumes</p>
</li>
<li>
<p>The <code>co_await</code> expression evaluates to the awaited task&#8217;s result</p>
</li>
</ol>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_lazy_execution"><a class="anchor" href="#_lazy_execution"></a>Lazy Execution</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A critical property of <code>task&lt;T&gt;</code> is <strong>lazy execution</strong>: creating a task does not start its execution. The coroutine body runs only when the task is awaited.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;int&gt; compute()
{
std::cout &lt;&lt; "Computing...\n"; // Not printed until awaited
co_return 42;
}
task&lt;&gt; example()
{
auto t = compute(); // Task created, but "Computing..." NOT printed yet
std::cout &lt;&lt; "Task created\n";
int result = co_await t; // NOW "Computing..." is printed
std::cout &lt;&lt; "Result: " &lt;&lt; result &lt;&lt; "\n";
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Output:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-asciidoc hljs" data-lang="asciidoc">Task created
Computing...
Result: 42</code></pre>
</div>
</div>
<div class="paragraph">
<p>Lazy execution enables efficient composition—tasks that are never awaited never run, consuming no resources beyond their initial allocation.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_symmetric_transfer"><a class="anchor" href="#_symmetric_transfer"></a>Symmetric Transfer</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When a task completes, control transfers directly to its continuation (the coroutine that awaited it) using <strong>symmetric transfer</strong>. This avoids stack accumulation even with deep chains of coroutine calls.</p>
</div>
<div class="paragraph">
<p>Consider:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;&gt; a() { co_await b(); }
task&lt;&gt; b() { co_await c(); }
task&lt;&gt; c() { co_return; }</code></pre>
</div>
</div>
<div class="paragraph">
<p>Without symmetric transfer, each <code>co_await</code> would add a stack frame, potentially causing stack overflow with deep nesting. With symmetric transfer, <code>c</code> returning to <code>b</code> returning to <code>a</code> uses constant stack space regardless of depth.</p>
</div>
<div class="paragraph">
<p>This is implemented through the <code>await_suspend</code> returning a coroutine handle rather than <code>void</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">// Inside task's final_suspend awaiter
std::coroutine_handle&lt;&gt; await_suspend(std::coroutine_handle&lt;&gt;) const noexcept
{
return continuation_; // Transfer directly to continuation
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_move_semantics"><a class="anchor" href="#_move_semantics"></a>Move Semantics</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Tasks are move-only. Copying a task would create aliasing problems where multiple handles reference the same coroutine frame.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;int&gt; compute();
task&lt;&gt; example()
{
auto t1 = compute();
auto t2 = std::move(t1); // OK: ownership transferred
// auto t3 = t2; // Error: task is not copyable
int result = co_await t2; // t1 is now empty
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>After moving, the source task becomes empty and must not be awaited.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_exception_propagation"><a class="anchor" href="#_exception_propagation"></a>Exception Propagation</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Exceptions thrown inside a task are captured and rethrown when the task is awaited:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;int&gt; might_fail(bool should_fail)
{
if (should_fail)
throw std::runtime_error("Operation failed");
co_return 42;
}
task&lt;&gt; example()
{
try
{
int result = co_await might_fail(true);
}
catch (std::runtime_error const&amp; e)
{
std::cout &lt;&lt; "Caught: " &lt;&lt; e.what() &lt;&lt; "\n";
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The exception is stored in the promise when it occurs and rethrown in <code>await_resume</code> when the calling coroutine resumes.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_reference"><a class="anchor" href="#_reference"></a>Reference</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <code>task&lt;T&gt;</code> type is defined in:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;boost/capy/task.hpp&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Or included via the umbrella header:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;boost/capy.hpp&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>You have now learned how to declare, return values from, and await <code>task&lt;T&gt;</code> coroutines. In the next section, you will learn how to launch tasks for execution using <code>run_async</code> and <code>run</code>.</p>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/4.coroutines/4a.tasks.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="4.intro.html">Coroutines in Capy</a></span>
<span class="next"><a href="4b.launching.html">Launching Coroutines</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,638 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Launching Coroutines :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/4.coroutines/4b.launching.html">
<link rel="prev" href="4a.tasks.html">
<link rel="next" href="4c.executors.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="4a.tasks.html">The task Type</a>
</li>
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="4.intro.html">Coroutines in Capy</a></li>
<li><a href="4b.launching.html">Launching Coroutines</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="4a.tasks.html">
<span class="material-symbols-outlined" title="Previous: The task Type">arrow_back</span>
</a>
<a accesskey="u" href="4.intro.html">
<span class="material-symbols-outlined" title="Up: Coroutines in Capy">arrow_upward</span>
</a>
<a accesskey="n" href="4c.executors.html">
<span class="material-symbols-outlined" title="Next: Executors and Execution Contexts">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Launching Coroutines</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section explains how to launch coroutines for execution. You will learn about <code>run_async</code> for entry from non-coroutine code and <code>run</code> for executor hopping within coroutine code.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Completed <a href="4a.tasks.html" class="xref page">The task Type</a></p>
</li>
<li>
<p>Understanding of lazy task execution</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_execution_model"><a class="anchor" href="#_the_execution_model"></a>The Execution Model</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Capy tasks are lazy—they do not execute until something drives them. Two mechanisms exist:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Awaiting</strong> — One coroutine awaits another (<code>co_await task</code>)</p>
</li>
<li>
<p><strong>Launching</strong> — Non-coroutine code initiates execution (<code>run_async</code>)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>When a task is awaited, the awaiting coroutine provides context: an executor for dispatching completion and a stop token for cancellation. But what about the first task in a chain? That task needs explicit launching.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_run_async_entry_from_non_coroutine_code"><a class="anchor" href="#_run_async_entry_from_non_coroutine_code"></a>run_async: Entry from Non-Coroutine Code</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>run_async</code> is the bridge between regular code and coroutine code. It takes an executor, creates the necessary context, and starts the task executing.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;boost/capy.hpp&gt;
using namespace boost::capy;
task&lt;int&gt; compute()
{
co_return 42;
}
int main()
{
thread_pool pool;
run_async(pool.get_executor())(compute());
// Task is now running on the thread pool
// pool destructor waits for work to complete
return 0;
}</code></pre>
</div>
</div>
<div class="sect2">
<h3 id="_two_call_syntax"><a class="anchor" href="#_two_call_syntax"></a>Two-Call Syntax</h3>
<div class="paragraph">
<p>Notice the unusual syntax: <code>run_async(executor)(task)</code>. This is intentional and relates to C&#43;&#43;17 evaluation order.</p>
</div>
<div class="paragraph">
<p>C&#43;&#43;17 guarantees that in the expression <code>f(a)(b)</code>:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>f(a)</code> is evaluated first, producing a callable</p>
</li>
<li>
<p><code>b</code> is evaluated second</p>
</li>
<li>
<p>The callable is invoked with <code>b</code></p>
</li>
</ol>
</div>
<div class="paragraph">
<p>This ordering matters because the task&#8217;s coroutine frame is allocated during step 2, and <code>run_async</code> sets up thread-local allocator state in step 1. The task inherits that allocator.</p>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Do not store the result of <code>run_async(executor)</code> and call it later:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">auto wrapper = run_async(pool.get_executor()); // Don't do this
wrapper(compute()); // TLS state no longer valid</code></pre>
</div>
</div>
<div class="paragraph">
<p>Always use the two-call pattern in a single expression.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="_handler_overloads"><a class="anchor" href="#_handler_overloads"></a>Handler Overloads</h3>
<div class="paragraph">
<p><code>run_async</code> accepts optional handlers for results and exceptions:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">// Result handler only (exceptions rethrown)
run_async(ex, [](int result) {
std::cout &lt;&lt; "Got: " &lt;&lt; result &lt;&lt; "\n";
})(compute());
// Separate handlers for result and exception
run_async(ex,
[](int result) { std::cout &lt;&lt; "Result: " &lt;&lt; result &lt;&lt; "\n"; },
[](std::exception_ptr ep) {
try { std::rethrow_exception(ep); }
catch (std::exception const&amp; e) {
std::cout &lt;&lt; "Error: " &lt;&lt; e.what() &lt;&lt; "\n";
}
}
)(compute());</code></pre>
</div>
</div>
<div class="paragraph">
<p>When no handlers are provided, results are discarded and exceptions are rethrown (causing <code>std::terminate</code> if uncaught).</p>
</div>
</div>
<div class="sect2">
<h3 id="_stop_token_support"><a class="anchor" href="#_stop_token_support"></a>Stop Token Support</h3>
<div class="paragraph">
<p>Pass a stop token to enable cooperative cancellation:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::stop_source source;
run_async(ex, source.get_token())(cancellable_task());
// Later, to request cancellation:
source.request_stop();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The stop token is propagated to the task and all tasks it awaits.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_run_executor_hopping_within_coroutines"><a class="anchor" href="#_run_executor_hopping_within_coroutines"></a>run: Executor Hopping Within Coroutines</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Inside a coroutine, use <code>run</code> to execute a child task on a different executor:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;int&gt; compute_on_pool(thread_pool&amp; pool)
{
// This task runs on whatever executor we're already on
// But this child task runs on the pool's executor:
int result = co_await run(pool.get_executor())(expensive_computation());
// After co_await, we're back on our original executor
co_return result;
}</code></pre>
</div>
</div>
<div class="sect2">
<h3 id="_executor_affinity"><a class="anchor" href="#_executor_affinity"></a>Executor Affinity</h3>
<div class="paragraph">
<p>By default, a task inherits its caller&#8217;s executor. This means completions are dispatched through that executor, ensuring thread affinity for thread-sensitive code.</p>
</div>
<div class="paragraph">
<p><code>run</code> overrides this inheritance for a specific child task, binding it to a different executor. The child task runs on the specified executor, and when it completes, the parent task resumes on its original executor.</p>
</div>
<div class="paragraph">
<p>This pattern is useful for:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Running CPU-intensive work on a thread pool</p>
</li>
<li>
<p>Performing I/O on an I/O-specific context</p>
</li>
<li>
<p>Ensuring UI updates happen on the UI thread</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_handler_threading"><a class="anchor" href="#_handler_threading"></a>Handler Threading</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Handlers passed to <code>run_async</code> are invoked on whatever thread the executor schedules:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">// If pool has 4 threads, the handler runs on one of those threads
run_async(pool.get_executor(), [](int result) {
// This runs on a pool thread, NOT the main thread
update_shared_state(result);
})(compute());</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you need results on a specific thread, use appropriate synchronization or dispatch mechanisms.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_reference"><a class="anchor" href="#_reference"></a>Reference</h2>
<div class="sectionbody">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 75%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Header</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/ex/run_async.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Entry point for launching tasks from non-coroutine code</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/ex/run.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Executor binding for child tasks within coroutines</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>You have now learned how to launch coroutines using <code>run_async</code> and bind child tasks to specific executors using <code>run</code>. In the next section, you will learn about executors and execution contexts in detail.</p>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/4.coroutines/4b.launching.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="4a.tasks.html">The task Type</a></span>
<span class="next"><a href="4c.executors.html">Executors and Execution Contexts</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,720 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Executors and Execution Contexts :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/4.coroutines/4c.executors.html">
<link rel="prev" href="4b.launching.html">
<link rel="next" href="4d.io-awaitable.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4b.launching.html">Launching Coroutines</a>
</li>
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="4.intro.html">Coroutines in Capy</a></li>
<li><a href="4c.executors.html">Executors and Execution Contexts</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="4b.launching.html">
<span class="material-symbols-outlined" title="Previous: Launching Coroutines">arrow_back</span>
</a>
<a accesskey="u" href="4.intro.html">
<span class="material-symbols-outlined" title="Up: Coroutines in Capy">arrow_upward</span>
</a>
<a accesskey="n" href="4d.io-awaitable.html">
<span class="material-symbols-outlined" title="Next: The IoAwaitable Protocol">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Executors and Execution Contexts</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section explains executors and execution contexts—the mechanisms that control where and how coroutines execute.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Completed <a href="4b.launching.html" class="xref page">Launching Coroutines</a></p>
</li>
<li>
<p>Understanding of <code>run_async</code> and <code>run</code></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_executor_concept"><a class="anchor" href="#_the_executor_concept"></a>The Executor Concept</h2>
<div class="sectionbody">
<div class="paragraph">
<p>An <strong>executor</strong> is an object that can schedule work for execution. In Capy, executors must provide two methods:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">concept Executor = requires(E ex, std::coroutine_handle&lt;&gt; h) {
{ ex.dispatch(h) } -&gt; std::same_as&lt;std::coroutine_handle&lt;&gt;&gt;;
{ ex.post(h) } -&gt; std::same_as&lt;void&gt;;
{ ex.context() } -&gt; std::convertible_to&lt;execution_context&amp;&gt;;
};</code></pre>
</div>
</div>
<div class="sect2">
<h3 id="_dispatch_vs_post"><a class="anchor" href="#_dispatch_vs_post"></a>dispatch() vs post()</h3>
<div class="paragraph">
<p>Both methods schedule a coroutine for execution, but with different semantics:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1"><code>dispatch(h)</code></dt>
<dd>
<p>May execute <code>h</code> inline if the current thread is already associated with the executor. Returns a coroutine handle—either <code>h</code> if execution was deferred, or <code>std::noop_coroutine()</code> if <code>h</code> was executed immediately. This enables symmetric transfer optimization.</p>
</dd>
<dt class="hdlist1"><code>post(h)</code></dt>
<dd>
<p>Always queues <code>h</code> for later execution. Never executes inline. Returns void. Use when you need guaranteed asynchrony.</p>
</dd>
</dl>
</div>
</div>
<div class="sect2">
<h3 id="_context"><a class="anchor" href="#_context"></a>context()</h3>
<div class="paragraph">
<p>Returns a reference to the execution context that owns this executor. The context provides resources like frame allocators.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_executor_ref_type_erased_executor"><a class="anchor" href="#_executor_ref_type_erased_executor"></a>executor_ref: Type-Erased Executor</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>executor_ref</code> wraps any executor in a type-erased container, allowing code to work with executors without knowing their concrete type:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">void schedule_work(executor_ref ex, std::coroutine_handle&lt;&gt; h)
{
ex.post(h); // Works with any executor
}
int main()
{
thread_pool pool;
executor_ref ex = pool.get_executor(); // Type erasure
schedule_work(ex, some_coroutine);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>executor_ref</code> stores a reference to the underlying executor—the original executor must outlive the <code>executor_ref</code>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_thread_pool_multi_threaded_execution"><a class="anchor" href="#_thread_pool_multi_threaded_execution"></a>thread_pool: Multi-Threaded Execution</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>thread_pool</code> manages a pool of worker threads that execute coroutines concurrently:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;boost/capy/ex/thread_pool.hpp&gt;
int main()
{
// Create pool with 4 threads
thread_pool pool(4);
// Get an executor for this pool
auto ex = pool.get_executor();
// Launch work on the pool
run_async(ex)(my_task());
// pool destructor waits for all work to complete
}</code></pre>
</div>
</div>
<div class="sect2">
<h3 id="_constructor_parameters"><a class="anchor" href="#_constructor_parameters"></a>Constructor Parameters</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">thread_pool(
std::size_t num_threads = 0,
std::string_view thread_name_prefix = "capy-pool-"
);</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p><code>num_threads</code> — Number of worker threads. If 0, uses hardware concurrency.</p>
</li>
<li>
<p><code>thread_name_prefix</code> — Prefix for thread names (useful for debugging).</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_thread_safety"><a class="anchor" href="#_thread_safety"></a>Thread Safety</h3>
<div class="paragraph">
<p>Work posted to a <code>thread_pool</code> may execute on any of its worker threads. If your coroutines access shared data, you must use appropriate synchronization.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_execution_context_base_class"><a class="anchor" href="#_execution_context_base_class"></a>execution_context: Base Class</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>execution_context</code> is the base class for execution contexts. It provides:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Frame allocator access via <code>get_frame_allocator()</code></p>
</li>
<li>
<p>Service infrastructure for extensibility</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Custom execution contexts inherit from <code>execution_context</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">class my_context : public execution_context
{
public:
// ... custom implementation
my_executor get_executor();
};</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_strand_serialization_without_mutexes"><a class="anchor" href="#_strand_serialization_without_mutexes"></a>strand: Serialization Without Mutexes</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A <code>strand</code> ensures that handlers are executed in order, with no two handlers executing concurrently. This eliminates the need for mutexes when all access to shared data goes through the strand.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;boost/capy/ex/strand.hpp&gt;
class shared_resource
{
strand&lt;thread_pool::executor_type&gt; strand_;
int counter_ = 0;
public:
explicit shared_resource(thread_pool&amp; pool)
: strand_(pool.get_executor())
{
}
task&lt;int&gt; increment()
{
// All increments are serialized through the strand
co_return co_await run(strand_)(do_increment());
}
private:
task&lt;int&gt; do_increment()
{
// No mutex needed—strand ensures exclusive access
++counter_;
co_return counter_;
}
};</code></pre>
</div>
</div>
<div class="sect2">
<h3 id="_how_strands_work"><a class="anchor" href="#_how_strands_work"></a>How Strands Work</h3>
<div class="paragraph">
<p>The strand maintains a queue of pending work. When work is dispatched:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>If no other work is executing on the strand, the new work runs immediately</p>
</li>
<li>
<p>If other work is executing, the new work is queued</p>
</li>
<li>
<p>When the current work completes, the next queued item runs</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>This provides logical single-threading without blocking physical threads.</p>
</div>
</div>
<div class="sect2">
<h3 id="_when_to_use_strands"><a class="anchor" href="#_when_to_use_strands"></a>When to Use Strands</h3>
<div class="ulist">
<ul>
<li>
<p><strong>Thread-affine resources</strong> — When code must not be called from multiple threads simultaneously</p>
</li>
<li>
<p><strong>Ordered operations</strong> — When operations must complete in a specific order</p>
</li>
<li>
<p><strong>Avoiding mutexes</strong> — When mutex overhead is unacceptable</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_single_threaded_vs_multi_threaded_patterns"><a class="anchor" href="#_single_threaded_vs_multi_threaded_patterns"></a>Single-Threaded vs Multi-Threaded Patterns</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_single_threaded"><a class="anchor" href="#_single_threaded"></a>Single-Threaded</h3>
<div class="paragraph">
<p>For single-threaded applications, use a context with one thread:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">thread_pool single_thread(1);
auto ex = single_thread.get_executor();
// All work runs on the single thread</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_multi_threaded_with_shared_data"><a class="anchor" href="#_multi_threaded_with_shared_data"></a>Multi-Threaded with Shared Data</h3>
<div class="paragraph">
<p>For multi-threaded applications with shared data, use strands:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">thread_pool pool(4);
strand&lt;thread_pool::executor_type&gt; data_strand(pool.get_executor());
// Use data_strand for all access to shared data
// Use pool.get_executor() for independent work</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_multi_threaded_with_independent_work"><a class="anchor" href="#_multi_threaded_with_independent_work"></a>Multi-Threaded with Independent Work</h3>
<div class="paragraph">
<p>For embarrassingly parallel work with no shared state:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">thread_pool pool(4);
auto ex = pool.get_executor();
// Launch independent tasks directly on the pool
std::vector&lt;task&lt;int&gt;&gt; tasks;
for (int i = 0; i &lt; 100; ++i)
run_async(ex)(independent_task(i));</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_reference"><a class="anchor" href="#_reference"></a>Reference</h2>
<div class="sectionbody">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 75%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Header</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/concept/executor.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The Executor concept definition</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/ex/executor_ref.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Type-erased executor wrapper</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/ex/thread_pool.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Multi-threaded execution context</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/ex/execution_context.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Base class for execution contexts</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/ex/strand.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Serialization primitive</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>You have now learned about executors, execution contexts, thread pools, and strands. In the next section, you will learn about the IoAwaitable protocol that enables context propagation.</p>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/4.coroutines/4c.executors.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="4b.launching.html">Launching Coroutines</a></span>
<span class="next"><a href="4d.io-awaitable.html">The IoAwaitable Protocol</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,693 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>The IoAwaitable Protocol :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/4.coroutines/4d.io-awaitable.html">
<link rel="prev" href="4c.executors.html">
<link rel="next" href="4e.cancellation.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="4.intro.html">Coroutines in Capy</a></li>
<li><a href="4d.io-awaitable.html">The IoAwaitable Protocol</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="4c.executors.html">
<span class="material-symbols-outlined" title="Previous: Executors and Execution Contexts">arrow_back</span>
</a>
<a accesskey="u" href="4.intro.html">
<span class="material-symbols-outlined" title="Up: Coroutines in Capy">arrow_upward</span>
</a>
<a accesskey="n" href="4e.cancellation.html">
<span class="material-symbols-outlined" title="Next: Stop Tokens and Cancellation">arrow_forward</span>
</a>
</div></div>
<h1 class="page">The IoAwaitable Protocol</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section explains the IoAwaitable protocol—Capy&#8217;s mechanism for propagating execution context through coroutine chains.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Completed <a href="4c.executors.html" class="xref page">Executors and Execution Contexts</a></p>
</li>
<li>
<p>Understanding of standard awaiter protocol (<code>await_ready</code>, <code>await_suspend</code>, <code>await_resume</code>)</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_problem_context_propagation"><a class="anchor" href="#_the_problem_context_propagation"></a>The Problem: Context Propagation</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Standard C&#43;&#43;20 coroutines define awaiters with this <code>await_suspend</code> signature:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">void await_suspend(std::coroutine_handle&lt;&gt; h);
// or
bool await_suspend(std::coroutine_handle&lt;&gt; h);
// or
std::coroutine_handle&lt;&gt; await_suspend(std::coroutine_handle&lt;&gt; h);</code></pre>
</div>
</div>
<div class="paragraph">
<p>The awaiter receives only a handle to the suspended coroutine. But real I/O code needs more:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Executor</strong> — Where should completions be dispatched?</p>
</li>
<li>
<p><strong>Stop token</strong> — Should this operation support cancellation?</p>
</li>
<li>
<p><strong>Allocator</strong> — Where should memory be allocated?</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>How does an awaitable get this information?</p>
</div>
<div class="sect2">
<h3 id="_backward_query_approach"><a class="anchor" href="#_backward_query_approach"></a>Backward Query Approach</h3>
<div class="paragraph">
<p>One approach: the awaitable queries the calling coroutine&#8217;s promise for context. This requires the awaitable to know the promise type, creating tight coupling.</p>
</div>
</div>
<div class="sect2">
<h3 id="_forward_propagation_approach"><a class="anchor" href="#_forward_propagation_approach"></a>Forward Propagation Approach</h3>
<div class="paragraph">
<p>Capy uses <strong>forward propagation</strong>: the caller passes context to the awaitable through an extended <code>await_suspend</code> signature.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_two_argument_await_suspend"><a class="anchor" href="#_the_two_argument_await_suspend"></a>The Two-Argument await_suspend</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The IoAwaitable protocol extends <code>await_suspend</code> to receive context:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::coroutine_handle&lt;&gt; await_suspend(std::coroutine_handle&lt;&gt; h, io_env const* env);</code></pre>
</div>
</div>
<div class="paragraph">
<p>This signature receives:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>h</code> — The coroutine handle (as in standard awaiters)</p>
</li>
<li>
<p><code>env</code> — The execution environment containing:</p>
<div class="ulist">
<ul>
<li>
<p><code>env&#8594;executor</code> — The caller&#8217;s executor for dispatching completions</p>
</li>
<li>
<p><code>env&#8594;stop_token</code> — A stop token for cooperative cancellation</p>
</li>
<li>
<p><code>env&#8594;frame_allocator</code> — An optional frame allocator</p>
</li>
</ul>
</div>
</li>
</ul>
</div>
<div class="paragraph">
<p>The return type enables symmetric transfer.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_ioawaitable_concept"><a class="anchor" href="#_ioawaitable_concept"></a>IoAwaitable Concept</h2>
<div class="sectionbody">
<div class="paragraph">
<p>An awaitable satisfies <code>IoAwaitable</code> if:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">template&lt;typename T&gt;
concept IoAwaitable = requires(T&amp; t, std::coroutine_handle&lt;&gt; h, io_env const* env) {
{ t.await_ready() } -&gt; std::convertible_to&lt;bool&gt;;
{ t.await_suspend(h, env) } -&gt; std::same_as&lt;std::coroutine_handle&lt;&gt;&gt;;
t.await_resume();
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>The key difference from standard awaitables is the two-argument <code>await_suspend</code> that receives the <code>io_env</code>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_iorunnable_concept"><a class="anchor" href="#_iorunnable_concept"></a>IoRunnable Concept</h2>
<div class="sectionbody">
<div class="paragraph">
<p>For tasks that can be launched from non-coroutine contexts, the <code>IoRunnable</code> concept refines <code>IoAwaitable</code> with:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>handle()</code> — Access the typed coroutine handle</p>
</li>
<li>
<p><code>release()</code> — Transfer ownership of the frame</p>
</li>
<li>
<p><code>exception()</code> — Check for captured exceptions</p>
</li>
<li>
<p><code>result()</code> — Access the result value (non-void tasks)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>These methods exist because launch functions like <code>run_async</code> cannot <code>co_await</code> the task directly. The trampoline must be allocated before the task type is known, so it type-erases the task through function pointers and needs a common API to manage lifetime and extract results.</p>
</div>
<div class="paragraph">
<p>Context injection methods (<code>set_environment</code>, <code>set_continuation</code>) are internal to the promise and not part of any concept. Launch functions access them through the typed handle provided by <code>handle()</code>.</p>
</div>
<div class="paragraph">
<p>Capy&#8217;s <code>task&lt;T&gt;</code> satisfies this concept.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_how_context_flows"><a class="anchor" href="#_how_context_flows"></a>How Context Flows</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When you write <code>co_await child_task()</code> inside a <code>task&lt;T&gt;</code>:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>The parent task&#8217;s <code>await_transform</code> intercepts the awaitable</p>
</li>
<li>
<p>It wraps the child in a transform awaiter</p>
</li>
<li>
<p>The transform awaiter&#8217;s <code>await_suspend</code> passes context:</p>
</li>
</ol>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">template&lt;class Awaitable&gt;
auto await_suspend(std::coroutine_handle&lt;Promise&gt; h)
{
// Forward caller's context to child
return awaitable_.await_suspend(h, promise_.environment());
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The child receives the parent&#8217;s executor and stop token automatically.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_why_forward_propagation"><a class="anchor" href="#_why_forward_propagation"></a>Why Forward Propagation?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Forward propagation offers several advantages:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Decoupling</strong> — Awaitables don&#8217;t need to know caller&#8217;s promise type</p>
</li>
<li>
<p><strong>Composability</strong> — Any IoAwaitable works with any IoRunnable task</p>
</li>
<li>
<p><strong>Explicit flow</strong> — Context flows downward through the call chain, not queried upward</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This design enables Capy&#8217;s type-erased wrappers (<code>any_stream</code>, etc.) to work without knowing the concrete executor type.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_implementing_custom_ioawaitables"><a class="anchor" href="#_implementing_custom_ioawaitables"></a>Implementing Custom IoAwaitables</h2>
<div class="sectionbody">
<div class="paragraph">
<p>To create a custom IoAwaitable:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">struct my_awaitable
{
io_env const* env_ = nullptr;
std::coroutine_handle&lt;&gt; continuation_;
result_type result_;
bool await_ready() const noexcept
{
return false; // Or true if result is immediately available
}
std::coroutine_handle&lt;&gt; await_suspend(std::coroutine_handle&lt;&gt; h, io_env const* env)
{
// Store pointer to environment, never copy
env_ = env;
continuation_ = h;
// Start async operation...
start_operation();
// Return noop to suspend
return std::noop_coroutine();
}
result_type await_resume()
{
return result_;
}
private:
void on_completion()
{
// Resume on caller's executor
env_-&gt;executor.dispatch(continuation_);
}
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>The key points:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Store the <code>io_env</code> as a pointer (<code>io_env const*</code>), never a copy. Launch functions guarantee the <code>io_env</code> outlives the awaitable&#8217;s operation.</p>
</li>
<li>
<p>Use the executor to dispatch completion</p>
</li>
<li>
<p>Respect the stop token for cancellation</p>
</li>
</ol>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_reference"><a class="anchor" href="#_reference"></a>Reference</h2>
<div class="sectionbody">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 75%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Header</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/concept/io_awaitable.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The IoAwaitable concept definition</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/concept/io_runnable.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The IoRunnable concept for launchable tasks</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>You have now learned how the IoAwaitable protocol enables context propagation through coroutine chains. In the next section, you will learn about stop tokens and cooperative cancellation.</p>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/4.coroutines/4d.io-awaitable.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="4c.executors.html">Executors and Execution Contexts</a></span>
<span class="next"><a href="4e.cancellation.html">Stop Tokens and Cancellation</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,953 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Stop Tokens and Cancellation :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/4.coroutines/4e.cancellation.html">
<link rel="prev" href="4d.io-awaitable.html">
<link rel="next" href="4f.composition.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="4.intro.html">Coroutines in Capy</a></li>
<li><a href="4e.cancellation.html">Stop Tokens and Cancellation</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="4d.io-awaitable.html">
<span class="material-symbols-outlined" title="Previous: The IoAwaitable Protocol">arrow_back</span>
</a>
<a accesskey="u" href="4.intro.html">
<span class="material-symbols-outlined" title="Up: Coroutines in Capy">arrow_upward</span>
</a>
<a accesskey="n" href="4f.composition.html">
<span class="material-symbols-outlined" title="Next: Concurrent Composition">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Stop Tokens and Cancellation</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section teaches cooperative cancellation from the ground up, explaining C&#43;&#43;20 stop tokens as a general-purpose notification mechanism and how Capy uses them for coroutine cancellation.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Completed <a href="4d.io-awaitable.html" class="xref page">The IoAwaitable Protocol</a></p>
</li>
<li>
<p>Understanding of how context propagates through coroutine chains</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_part_1_the_problem"><a class="anchor" href="#_part_1_the_problem"></a>Part 1: The Problem</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Cancellation matters in many scenarios:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A user clicks "Cancel" on a download dialog</p>
</li>
<li>
<p>A timeout expires while waiting for a network response</p>
</li>
<li>
<p>A connection drops unexpectedly</p>
</li>
<li>
<p>An application is shutting down</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_the_naive_approach_boolean_flags"><a class="anchor" href="#_the_naive_approach_boolean_flags"></a>The Naive Approach: Boolean Flags</h3>
<div class="paragraph">
<p>The obvious solution seems to be a boolean flag:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::atomic&lt;bool&gt; should_cancel{false};
void worker()
{
while (!should_cancel)
{
do_work();
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This approach has problems:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>No standardization</strong> — Every component invents its own cancellation flag</p>
</li>
<li>
<p><strong>Race conditions</strong> — Checking the flag and acting on it is not atomic</p>
</li>
<li>
<p><strong>No cleanup notification</strong> — The worker just stops; no opportunity for graceful cleanup</p>
</li>
<li>
<p><strong>Polling overhead</strong> — Must check the flag repeatedly</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_the_thread_interruption_problem"><a class="anchor" href="#_the_thread_interruption_problem"></a>The Thread Interruption Problem</h3>
<div class="paragraph">
<p>Some systems support forceful thread interruption. This is dangerous because it can leave resources in inconsistent states—files half-written, locks held, transactions uncommitted.</p>
</div>
</div>
<div class="sect2">
<h3 id="_the_goal_cooperative_cancellation"><a class="anchor" href="#_the_goal_cooperative_cancellation"></a>The Goal: Cooperative Cancellation</h3>
<div class="paragraph">
<p>The solution is <strong>cooperative cancellation</strong>: ask nicely, let the work clean up. The cancellation requestor signals intent; the worker decides when and how to respond.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_part_2_c20_stop_tokensa_general_purpose_signaling_mechanism"><a class="anchor" href="#_part_2_c20_stop_tokensa_general_purpose_signaling_mechanism"></a>Part 2: C&#43;&#43;20 Stop Tokens—A General-Purpose Signaling Mechanism</h2>
<div class="sectionbody">
<div class="paragraph">
<p>C&#43;&#43;20 introduces <code>std::stop_token</code>, <code>std::stop_source</code>, and <code>std::stop_callback</code>. While named for "stopping," these implement a general-purpose <strong>Observer pattern</strong>—a thread-safe one-to-many notification system.</p>
</div>
<div class="sect2">
<h3 id="_the_three_components"><a class="anchor" href="#_the_three_components"></a>The Three Components</h3>
<div class="dlist">
<dl>
<dt class="hdlist1"><code>std::stop_source</code></dt>
<dd>
<p>The <strong>Subject/Publisher</strong>. Owns the shared state and can trigger notifications. Create one source, then distribute tokens to observers.</p>
</dd>
<dt class="hdlist1"><code>std::stop_token</code></dt>
<dd>
<p>The <strong>Subscriber View</strong>. A read-only, copyable, cheap-to-pass-around handle. Multiple tokens can share the same underlying state.</p>
</dd>
<dt class="hdlist1"><code>std::stop_callback&lt;F&gt;</code></dt>
<dd>
<p>The <strong>Observer Registration</strong>. An RAII object that registers a callback to run when signaled. Destruction automatically unregisters.</p>
</dd>
</dl>
</div>
</div>
<div class="sect2">
<h3 id="_how_they_work_together"><a class="anchor" href="#_how_they_work_together"></a>How They Work Together</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;stop_token&gt;
#include &lt;iostream&gt;
void example()
{
std::stop_source source;
// Create tokens (distribute notification capability)
std::stop_token token1 = source.get_token();
std::stop_token token2 = source.get_token(); // Same underlying state
// Register callbacks (observers)
std::stop_callback cb1(token1, []{ std::cout &lt;&lt; "Observer 1 notified\n"; });
std::stop_callback cb2(token2, []{ std::cout &lt;&lt; "Observer 2 notified\n"; });
std::cout &lt;&lt; "Before signal\n";
source.request_stop(); // Triggers all callbacks
std::cout &lt;&lt; "After signal\n";
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Output:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-asciidoc hljs" data-lang="asciidoc">Before signal
Observer 1 notified
Observer 2 notified
After signal</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_immediate_invocation"><a class="anchor" href="#_immediate_invocation"></a>Immediate Invocation</h3>
<div class="paragraph">
<p>If a callback is registered after <code>request_stop()</code> was already called, the callback runs <strong>immediately</strong> in the constructor:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::stop_source source;
source.request_stop(); // Already signaled
// Callback runs in constructor, not later
std::stop_callback cb(source.get_token(), []{
std::cout &lt;&lt; "Runs immediately!\n";
});</code></pre>
</div>
</div>
<div class="paragraph">
<p>This ensures observers never miss the signal, regardless of registration timing.</p>
</div>
</div>
<div class="sect2">
<h3 id="_type_erased_polymorphic_observers"><a class="anchor" href="#_type_erased_polymorphic_observers"></a>Type-Erased Polymorphic Observers</h3>
<div class="paragraph">
<p>Each <code>stop_callback&lt;F&gt;</code> stores a different callable type <code>F</code>. Despite this, all callbacks for a given source can be invoked uniformly. This is equivalent to having <code>vector&lt;function&lt;void()&gt;&gt;</code> but with:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>No heap allocation per callback</p>
</li>
<li>
<p>No virtual function overhead</p>
</li>
<li>
<p>RAII lifetime management</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_thread_safety"><a class="anchor" href="#_thread_safety"></a>Thread Safety</h3>
<div class="paragraph">
<p>Registration and invocation are thread-safe. You can register callbacks, request stop, and invoke callbacks from any thread without additional synchronization.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_part_3_the_one_shot_nature"><a class="anchor" href="#_part_3_the_one_shot_nature"></a>Part 3: The One-Shot Nature</h2>
<div class="sectionbody">
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
<div class="paragraph">
<p><strong>Critical limitation</strong>: <code>stop_token</code> is a <strong>one-shot</strong> mechanism.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Can only transition from "not signaled" to "signaled" once</p>
</li>
<li>
<p>No reset mechanism—once <code>stop_requested()</code> returns true, it stays true forever</p>
</li>
<li>
<p><code>request_stop()</code> returns <code>true</code> only on the first successful call</p>
</li>
<li>
<p><strong>You cannot "un-cancel" a stop_source</strong></p>
</li>
</ul>
</div>
</td>
</tr>
</table>
</div>
<div class="sect2">
<h3 id="_why_this_matters"><a class="anchor" href="#_why_this_matters"></a>Why This Matters</h3>
<div class="paragraph">
<p>If you design a system that needs to cancel and restart operations, you cannot reuse the same <code>stop_source</code>. Each cycle requires a fresh source and fresh tokens.</p>
</div>
</div>
<div class="sect2">
<h3 id="_the_reset_workaround"><a class="anchor" href="#_the_reset_workaround"></a>The Reset Workaround</h3>
<div class="paragraph">
<p>To "reset," create an entirely new <code>stop_source</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::stop_source source;
auto token = source.get_token();
// ... distribute token to workers ...
source.request_stop(); // Triggered, now permanently signaled
// To "reset": create new source
source = std::stop_source{}; // New shared state
// Old tokens are now orphaned (stop_possible() returns false)
// Must redistribute new tokens to ALL holders of the old token
auto new_token = source.get_token();</code></pre>
</div>
</div>
<div class="paragraph">
<p>This is manual and error-prone. Any code still holding the old token will not receive new signals.</p>
</div>
</div>
<div class="sect2">
<h3 id="_design_implication"><a class="anchor" href="#_design_implication"></a>Design Implication</h3>
<div class="paragraph">
<p>If you need repeatable signals, <code>stop_token</code> is the wrong tool. Consider:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Condition variables for repeatable wake-ups</p>
</li>
<li>
<p>Atomic flags with explicit reset protocol</p>
</li>
<li>
<p>Custom event types</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_part_4_beyond_cancellation"><a class="anchor" href="#_part_4_beyond_cancellation"></a>Part 4: Beyond Cancellation</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The "stop" naming obscures the mechanism&#8217;s generality. <code>stop_token</code> implements <strong>one-shot broadcast notification</strong>, useful for:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Starting things</strong> — Signal "ready" to trigger initialization</p>
</li>
<li>
<p><strong>Configuration loaded</strong> — Notify components when config is available</p>
</li>
<li>
<p><strong>Resource availability</strong> — Signal when database connected or cache warmed</p>
</li>
<li>
<p><strong>Any one-shot broadcast scenario</strong></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_part_5_stop_tokens_in_coroutines"><a class="anchor" href="#_part_5_stop_tokens_in_coroutines"></a>Part 5: Stop Tokens in Coroutines</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Coroutines have a propagation problem: how does a nested coroutine know to stop? If you pass a stop token explicitly to every function, your APIs become cluttered.</p>
</div>
<div class="sect2">
<h3 id="_capys_answer_automatic_propagation"><a class="anchor" href="#_capys_answer_automatic_propagation"></a>Capy&#8217;s Answer: Automatic Propagation</h3>
<div class="paragraph">
<p>Capy propagates stop tokens downward through <code>co_await</code>. When you await a task, the IoAwaitable protocol passes the current stop token to the child:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;&gt; parent()
{
// Our stop token is automatically passed to child
co_await child();
}
task&lt;&gt; child()
{
// Receives parent's stop token via IoAwaitable protocol
auto token = co_await get_stop_token(); // Access current token
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>No manual threading—the protocol handles it.</p>
</div>
</div>
<div class="sect2">
<h3 id="_accessing_the_stop_token"><a class="anchor" href="#_accessing_the_stop_token"></a>Accessing the Stop Token</h3>
<div class="paragraph">
<p>Inside a task, use <code>get_stop_token()</code> to access the current stop token:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;&gt; cancellable_work()
{
auto token = co_await get_stop_token();
while (!token.stop_requested())
{
co_await do_chunk_of_work();
}
}</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_part_6_responding_to_cancellation"><a class="anchor" href="#_part_6_responding_to_cancellation"></a>Part 6: Responding to Cancellation</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_checking_the_token"><a class="anchor" href="#_checking_the_token"></a>Checking the Token</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;&gt; process_items(std::vector&lt;Item&gt; const&amp; items)
{
auto token = co_await get_stop_token();
for (auto const&amp; item : items)
{
if (token.stop_requested())
co_return; // Exit early
co_await process(item);
}
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_cleanup_with_raii"><a class="anchor" href="#_cleanup_with_raii"></a>Cleanup with RAII</h3>
<div class="paragraph">
<p>RAII ensures resources are released on early exit:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;&gt; with_resource()
{
auto resource = acquire_resource(); // RAII wrapper
auto token = co_await get_stop_token();
while (!token.stop_requested())
{
co_await use_resource(resource);
}
// resource destructor runs regardless of how we exit
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_the_operation_aborted_convention"><a class="anchor" href="#_the_operation_aborted_convention"></a>The operation_aborted Convention</h3>
<div class="paragraph">
<p>When cancellation causes an operation to fail, the conventional error code is <code>error::operation_aborted</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;std::string&gt; fetch_with_cancel()
{
auto token = co_await get_stop_token();
if (token.stop_requested())
{
throw std::system_error(
make_error_code(std::errc::operation_canceled));
}
co_return co_await do_fetch();
}</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_part_7_os_integration"><a class="anchor" href="#_part_7_os_integration"></a>Part 7: OS Integration</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Capy&#8217;s I/O operations (provided by Corosio) respect stop tokens at the OS level:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>IOCP</strong> (Windows) — Pending operations can be cancelled via <code>CancelIoEx</code></p>
</li>
<li>
<p><strong>io_uring</strong> (Linux) — Operations can be cancelled via <code>IORING_OP_ASYNC_CANCEL</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>When you request stop, pending I/O operations are cancelled at the OS level, providing immediate response rather than waiting for the operation to complete naturally.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_part_8_patterns"><a class="anchor" href="#_part_8_patterns"></a>Part 8: Patterns</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_timeout_pattern"><a class="anchor" href="#_timeout_pattern"></a>Timeout Pattern</h3>
<div class="paragraph">
<p>Combine a timer with stop token to implement timeouts:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;&gt; with_timeout(task&lt;&gt; operation, std::chrono::seconds timeout)
{
std::stop_source source;
// Timer that requests stop after timeout
auto timer = co_await start_timer(timeout, [&amp;source] {
source.request_stop();
});
// Run operation with our stop token
co_await run_with_token(source.get_token(), std::move(operation));
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_user_cancellation"><a class="anchor" href="#_user_cancellation"></a>User Cancellation</h3>
<div class="paragraph">
<p>Connect UI cancellation to stop tokens:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">class download_manager
{
std::stop_source stop_source_;
public:
void start_download(std::string url)
{
run_async(executor_)(download(url, stop_source_.get_token()));
}
void cancel()
{
stop_source_.request_stop();
}
};</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_graceful_shutdown"><a class="anchor" href="#_graceful_shutdown"></a>Graceful Shutdown</h3>
<div class="paragraph">
<p>Cancel all pending work during shutdown:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">class server
{
std::stop_source shutdown_source_;
public:
void shutdown()
{
shutdown_source_.request_stop();
// All pending operations receive stop request
}
task&lt;&gt; handle_connection(connection conn)
{
auto token = shutdown_source_.get_token();
while (!token.stop_requested())
{
co_await process_request(conn);
}
// Graceful cleanup
co_await send_goodbye(conn);
}
};</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_when_any_cancellation"><a class="anchor" href="#_when_any_cancellation"></a>when_any Cancellation</h3>
<div class="paragraph">
<p><code>when_any</code> uses stop tokens internally to cancel "losing" tasks when the first task completes. This is covered in <a href="4f.composition.html" class="xref page">Concurrent Composition</a>.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_reference"><a class="anchor" href="#_reference"></a>Reference</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The stop token mechanism is part of the C&#43;&#43; standard library:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;stop_token&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Key types:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>std::stop_source</code> — Creates and manages stop state</p>
</li>
<li>
<p><code>std::stop_token</code> — Observes stop state</p>
</li>
<li>
<p><code>std::stop_callback&lt;F&gt;</code> — Registers callbacks for stop notification</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>You have now learned how stop tokens provide cooperative cancellation for coroutines. In the next section, you will learn about concurrent composition with <code>when_all</code> and <code>when_any</code>.</p>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/4.coroutines/4e.cancellation.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="4d.io-awaitable.html">The IoAwaitable Protocol</a></span>
<span class="next"><a href="4f.composition.html">Concurrent Composition</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,734 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Concurrent Composition :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/4.coroutines/4f.composition.html">
<link rel="prev" href="4e.cancellation.html">
<link rel="next" href="4g.allocators.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="4.intro.html">Coroutines in Capy</a></li>
<li><a href="4f.composition.html">Concurrent Composition</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="4e.cancellation.html">
<span class="material-symbols-outlined" title="Previous: Stop Tokens and Cancellation">arrow_back</span>
</a>
<a accesskey="u" href="4.intro.html">
<span class="material-symbols-outlined" title="Up: Coroutines in Capy">arrow_upward</span>
</a>
<a accesskey="n" href="4g.allocators.html">
<span class="material-symbols-outlined" title="Next: Frame Allocators">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Concurrent Composition</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section explains how to run multiple tasks concurrently using <code>when_all</code> and <code>when_any</code>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Completed <a href="4e.cancellation.html" class="xref page">Stop Tokens and Cancellation</a></p>
</li>
<li>
<p>Understanding of stop token propagation</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_overview"><a class="anchor" href="#_overview"></a>Overview</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Sequential execution—one task after another—is the default when using <code>co_await</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;&gt; sequential()
{
co_await task_a(); // Wait for A
co_await task_b(); // Then wait for B
co_await task_c(); // Then wait for C
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>For independent operations, concurrent execution is more efficient:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;&gt; concurrent()
{
// Run A, B, C simultaneously
co_await when_all(task_a(), task_b(), task_c());
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_when_all_wait_for_all_tasks"><a class="anchor" href="#_when_all_wait_for_all_tasks"></a>when_all: Wait for All Tasks</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>when_all</code> launches multiple tasks concurrently and waits for all of them to complete:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;boost/capy/when_all.hpp&gt;
task&lt;int&gt; fetch_a() { co_return 1; }
task&lt;int&gt; fetch_b() { co_return 2; }
task&lt;std::string&gt; fetch_c() { co_return "hello"; }
task&lt;&gt; example()
{
auto [a, b, c] = co_await when_all(fetch_a(), fetch_b(), fetch_c());
// a == 1
// b == 2
// c == "hello"
}</code></pre>
</div>
</div>
<div class="sect2">
<h3 id="_result_tuple"><a class="anchor" href="#_result_tuple"></a>Result Tuple</h3>
<div class="paragraph">
<p><code>when_all</code> returns a tuple of results in the same order as the input tasks. Use structured bindings to unpack them.</p>
</div>
</div>
<div class="sect2">
<h3 id="_void_filtering"><a class="anchor" href="#_void_filtering"></a>Void Filtering</h3>
<div class="paragraph">
<p>Tasks returning <code>void</code> do not contribute to the result tuple:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;&gt; void_task() { co_return; }
task&lt;int&gt; int_task() { co_return 42; }
task&lt;&gt; example()
{
auto [value] = co_await when_all(void_task(), int_task(), void_task());
// value == 42 (only the int_task contributes)
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>If all tasks return <code>void</code>, <code>when_all</code> returns <code>void</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;&gt; example()
{
co_await when_all(void_task_a(), void_task_b()); // Returns void
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_error_handling"><a class="anchor" href="#_error_handling"></a>Error Handling</h3>
<div class="paragraph">
<p>If any task throws an exception:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>The exception is captured</p>
</li>
<li>
<p>Stop is requested for sibling tasks</p>
</li>
<li>
<p>All tasks are allowed to complete (or respond to stop)</p>
</li>
<li>
<p>The <strong>first</strong> exception is rethrown; later exceptions are discarded</p>
</li>
</ol>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;int&gt; might_fail(bool fail)
{
if (fail)
throw std::runtime_error("failed");
co_return 42;
}
task&lt;&gt; example()
{
try
{
co_await when_all(might_fail(true), might_fail(false));
}
catch (std::runtime_error const&amp; e)
{
// Catches the exception from the failing task
}
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_stop_propagation"><a class="anchor" href="#_stop_propagation"></a>Stop Propagation</h3>
<div class="paragraph">
<p>When one task fails, <code>when_all</code> requests stop for its siblings. Well-behaved tasks should check their stop token and exit promptly:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;&gt; long_running()
{
auto token = co_await get_stop_token();
for (int i = 0; i &lt; 1000; ++i)
{
if (token.stop_requested())
co_return; // Exit early when sibling fails
co_await do_iteration();
}
}</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_when_any_first_to_finish_wins"><a class="anchor" href="#_when_any_first_to_finish_wins"></a>when_any: First-to-Finish Wins</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>when_any</code> launches multiple tasks concurrently and returns when the <strong>first</strong> one completes:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;boost/capy/when_any.hpp&gt;
task&lt;&gt; example()
{
auto [index, result] = co_await when_any(
fetch_int(), // task&lt;int&gt;
fetch_string() // task&lt;std::string&gt;
);
// index indicates which task won (0 or 1)
// result is std::variant&lt;int, std::string&gt;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The result is a pair containing the winner&#8217;s index and a deduplicated variant of possible result types. When a winner is determined, stop is requested for all siblings. All tasks complete before <code>when_any</code> returns.</p>
</div>
<div class="paragraph">
<p>For detailed coverage including error handling, cancellation, and the vector overload, see Racing Tasks.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_practical_patterns"><a class="anchor" href="#_practical_patterns"></a>Practical Patterns</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_parallel_fetch"><a class="anchor" href="#_parallel_fetch"></a>Parallel Fetch</h3>
<div class="paragraph">
<p>Fetch multiple resources simultaneously:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;page_data&gt; fetch_page_data(std::string url)
{
auto [header, body, sidebar] = co_await when_all(
fetch_header(url),
fetch_body(url),
fetch_sidebar(url)
);
co_return page_data{
std::move(header),
std::move(body),
std::move(sidebar)
};
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_fan_outfan_in"><a class="anchor" href="#_fan_outfan_in"></a>Fan-Out/Fan-In</h3>
<div class="paragraph">
<p>Process items in parallel, then combine results:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;int&gt; process_item(item const&amp; i);
task&lt;int&gt; process_all(std::vector&lt;item&gt; const&amp; items)
{
std::vector&lt;task&lt;int&gt;&gt; tasks;
for (auto const&amp; item : items)
tasks.push_back(process_item(item));
// This requires a range-based when_all (not yet available)
// For now, use fixed-arity when_all
int total = 0;
// ... accumulate results
co_return total;
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_timeout_with_fallback"><a class="anchor" href="#_timeout_with_fallback"></a>Timeout with Fallback</h3>
<div class="paragraph">
<p>Use <code>when_any</code> to implement timeout with fallback:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">task&lt;Response&gt; fetch_with_timeout(Request req)
{
auto [index, result] = co_await when_any(
fetch_data(req),
timeout_after&lt;Response&gt;(100ms)
);
if (index == 1)
throw timeout_error{"Request timed out"};
co_return std::get&lt;Response&gt;(result);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>timeout_after</code> helper waits for the specified duration then throws. If <code>fetch_data</code> completes first, its result is returned. If the timer wins, the timeout exception propagates.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_implementation_notes"><a class="anchor" href="#_implementation_notes"></a>Implementation Notes</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_task_storage"><a class="anchor" href="#_task_storage"></a>Task Storage</h3>
<div class="paragraph">
<p><code>when_all</code> stores all tasks in its coroutine frame. Tasks are moved from the arguments, so the original task objects become empty after the call.</p>
</div>
</div>
<div class="sect2">
<h3 id="_completion_tracking"><a class="anchor" href="#_completion_tracking"></a>Completion Tracking</h3>
<div class="paragraph">
<p>A shared atomic counter tracks how many tasks remain. Each task completion decrements the counter. When it reaches zero, the parent coroutine is resumed.</p>
</div>
</div>
<div class="sect2">
<h3 id="_runner_coroutines"><a class="anchor" href="#_runner_coroutines"></a>Runner Coroutines</h3>
<div class="paragraph">
<p>Each child task is wrapped in a "runner" coroutine that:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Receives context (executor, stop token) from <code>when_all</code></p>
</li>
<li>
<p>Awaits the child task</p>
</li>
<li>
<p>Stores the result in shared state</p>
</li>
<li>
<p>Signals completion</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>This design ensures proper context propagation to all children.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_reference"><a class="anchor" href="#_reference"></a>Reference</h2>
<div class="sectionbody">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 75%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Header</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/when_all.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Concurrent composition with when_all</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/when_any.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">First-completion racing with when_any</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>You have now learned how to compose tasks concurrently with <code>when_all</code> and <code>when_any</code>. In the next section, you will learn about frame allocators for customizing coroutine memory allocation.</p>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/4.coroutines/4f.composition.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="4e.cancellation.html">Stop Tokens and Cancellation</a></span>
<span class="next"><a href="4g.allocators.html">Frame Allocators</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,682 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Frame Allocators :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/4.coroutines/4g.allocators.html">
<link rel="prev" href="4f.composition.html">
<link rel="next" href="../5.buffers/5.intro.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="4f.composition.html">Concurrent Composition</a>
</li>
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../5.buffers/5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../5.buffers/5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="4.intro.html">Coroutines in Capy</a></li>
<li><a href="4g.allocators.html">Frame Allocators</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="4f.composition.html">
<span class="material-symbols-outlined" title="Previous: Concurrent Composition">arrow_back</span>
</a>
<a accesskey="u" href="4.intro.html">
<span class="material-symbols-outlined" title="Up: Coroutines in Capy">arrow_upward</span>
</a>
<a accesskey="n" href="../5.buffers/5.intro.html">
<span class="material-symbols-outlined" title="Next: Buffer Sequences">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Frame Allocators</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section explains how coroutine frames are allocated and how to customize allocation for performance.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Completed <a href="4f.composition.html" class="xref page">Concurrent Composition</a></p>
</li>
<li>
<p>Understanding of coroutine frame allocation from <a href="../2.cpp20-coroutines/2d.advanced.html" class="xref page">C&#43;&#43;20 Coroutines Tutorial</a></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_timing_constraint"><a class="anchor" href="#_the_timing_constraint"></a>The Timing Constraint</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Coroutine frame allocation has a unique constraint: memory must be allocated <strong>before</strong> the coroutine body begins executing. The standard C&#43;&#43; mechanism—promise type&#8217;s <code>operator new</code>—is called before the promise is constructed.</p>
</div>
<div class="paragraph">
<p>This creates a challenge: how can a coroutine use a custom allocator when the allocator might be passed as a parameter, which is stored <strong>in</strong> the frame?</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_thread_local_propagation"><a class="anchor" href="#_thread_local_propagation"></a>Thread-Local Propagation</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Capy solves this with thread-local propagation:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Before evaluating the task argument, <code>run_async</code> sets a thread-local allocator</p>
</li>
<li>
<p>The task&#8217;s <code>operator new</code> reads this thread-local allocator</p>
</li>
<li>
<p>The task stores the allocator in its promise for child propagation</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>This is why <code>run_async</code> uses two-call syntax:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">run_async(executor)(my_task());
// ↑ ↑
// 1. Sets 2. Task allocated
// TLS using TLS allocator</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_window"><a class="anchor" href="#_the_window"></a>The Window</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The "window" is the interval between setting the thread-local allocator and the coroutine&#8217;s first suspension point. During this window:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The task is allocated using the TLS allocator</p>
</li>
<li>
<p>The task captures the TLS allocator in its promise</p>
</li>
<li>
<p>Child tasks inherit the allocator</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>After the window closes (at the first suspension), the TLS allocator may be restored to a previous value. The task retains its captured allocator regardless.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_frameallocator_concept"><a class="anchor" href="#_the_frameallocator_concept"></a>The FrameAllocator Concept</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Custom allocators must satisfy the <code>FrameAllocator</code> concept, which is compatible with C&#43;&#43; allocator requirements:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">template&lt;typename A&gt;
concept FrameAllocator = requires {
typename A::value_type;
} &amp;&amp; requires(A&amp; a, std::size_t n) {
{ a.allocate(n) } -&gt; std::same_as&lt;typename A::value_type*&gt;;
{ a.deallocate(std::declval&lt;typename A::value_type*&gt;(), n) };
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>In practice, any standard allocator works.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_using_custom_allocators"><a class="anchor" href="#_using_custom_allocators"></a>Using Custom Allocators</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_with_run_async"><a class="anchor" href="#_with_run_async"></a>With run_async</h3>
<div class="paragraph">
<p>Pass an allocator to <code>run_async</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::pmr::monotonic_buffer_resource resource;
std::pmr::polymorphic_allocator&lt;std::byte&gt; alloc(&amp;resource);
run_async(executor, alloc)(my_task());</code></pre>
</div>
</div>
<div class="paragraph">
<p>Or pass a <code>memory_resource*</code> directly:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">std::pmr::monotonic_buffer_resource resource;
run_async(executor, &amp;resource)(my_task());</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_default_allocator"><a class="anchor" href="#_default_allocator"></a>Default Allocator</h3>
<div class="paragraph">
<p>When no allocator is specified, <code>run_async</code> uses the execution context&#8217;s default frame allocator, typically a recycling allocator optimized for coroutine frame sizes.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_recycling_allocator"><a class="anchor" href="#_recycling_allocator"></a>Recycling Allocator</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Capy provides <code>recycling_memory_resource</code>, a memory resource optimized for coroutine frames:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Maintains freelists by size class</p>
</li>
<li>
<p>Reuses recently freed blocks (cache-friendly)</p>
</li>
<li>
<p>Falls back to upstream allocator for new sizes</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This allocator is used by default for <code>thread_pool</code> and other execution contexts.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_halo_optimization"><a class="anchor" href="#_halo_optimization"></a>HALO Optimization</h2>
<div class="sectionbody">
<div class="paragraph">
<p><strong>Heap Allocation eLision Optimization</strong> (HALO) allows the compiler to allocate coroutine frames on the stack instead of the heap when:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The coroutine&#8217;s lifetime is provably contained in the caller&#8217;s</p>
</li>
<li>
<p>The frame size is known at compile time</p>
</li>
<li>
<p>Optimization is enabled</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Capy&#8217;s <code>task&lt;T&gt;</code> uses the <code><a id="clang::coro_await_elidable"></a></code> attribute (when available) to enable HALO:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">template&lt;typename T = void&gt;
struct [[nodiscard]] BOOST_CAPY_CORO_AWAIT_ELIDABLE
task
{
// ...
};</code></pre>
</div>
</div>
<div class="sect2">
<h3 id="_when_halo_applies"><a class="anchor" href="#_when_halo_applies"></a>When HALO Applies</h3>
<div class="paragraph">
<p>HALO is most effective for immediately-awaited tasks:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">// HALO can apply: task is awaited immediately
int result = co_await compute();
// HALO cannot apply: task escapes to storage
auto t = compute();
tasks.push_back(std::move(t));</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_measuring_halo_effectiveness"><a class="anchor" href="#_measuring_halo_effectiveness"></a>Measuring HALO Effectiveness</h3>
<div class="paragraph">
<p>Profile your application to see if HALO is taking effect. Look for:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Reduced heap allocations</p>
</li>
<li>
<p>Improved cache locality</p>
</li>
<li>
<p>Lower allocation latency</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_best_practices"><a class="anchor" href="#_best_practices"></a>Best Practices</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_use_default_allocators"><a class="anchor" href="#_use_default_allocators"></a>Use Default Allocators</h3>
<div class="paragraph">
<p>For most applications, the default recycling allocator provides good performance without configuration.</p>
</div>
</div>
<div class="sect2">
<h3 id="_consider_memory_resources_for_batched_work"><a class="anchor" href="#_consider_memory_resources_for_batched_work"></a>Consider Memory Resources for Batched Work</h3>
<div class="paragraph">
<p>When launching many short-lived tasks together, a monotonic buffer resource can be efficient:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">void process_batch(std::vector&lt;item&gt; const&amp; items)
{
std::array&lt;std::byte, 64 * 1024&gt; buffer;
std::pmr::monotonic_buffer_resource resource(
buffer.data(), buffer.size());
for (auto const&amp; item : items)
{
run_async(executor, &amp;resource)(process(item));
}
// All frames deallocated when resource goes out of scope
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_profile_before_optimizing"><a class="anchor" href="#_profile_before_optimizing"></a>Profile Before Optimizing</h3>
<div class="paragraph">
<p>Coroutine frame allocation is rarely the bottleneck. Profile your application before investing in custom allocators.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_reference"><a class="anchor" href="#_reference"></a>Reference</h2>
<div class="sectionbody">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 75%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Header</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/ex/frame_allocator.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Frame allocator concept and utilities</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/ex/recycling_memory_resource.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Default recycling allocator implementation</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>You have now learned how coroutine frame allocation works and how to customize it. This completes the Coroutines in Capy section. Continue to <a href="../5.buffers/5a.overview.html" class="xref page">Buffer Sequences</a> to learn about Capy&#8217;s buffer model.</p>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/4.coroutines/4g.allocators.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="4f.composition.html">Concurrent Composition</a></span>
<span class="next"><a href="../5.buffers/5.intro.html">Buffer Sequences</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,386 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Buffer Sequences :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/5.buffers/5.intro.html">
<link rel="prev" href="../4.coroutines/4g.allocators.html">
<link rel="next" href="5a.overview.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../4.coroutines/4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class=" is-current-page" data-depth="1">
<a class="nav-link" href="5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="5.intro.html">Buffer Sequences</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="../4.coroutines/4g.allocators.html">
<span class="material-symbols-outlined" title="Previous: Frame Allocators">arrow_back</span>
</a>
<a class="disabled" accesskey="u" aria-disabled="true" tabindex="-1">
<span class="material-symbols-outlined" title="Up:">arrow_upward</span>
</a>
<a accesskey="n" href="5a.overview.html">
<span class="material-symbols-outlined" title="Next: Why Concepts, Not Spans">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Buffer Sequences</h1>
<div class="paragraph">
<p>Every I/O operation ultimately comes down to moving bytes between your program and the outside world&#8212;&#8203;a socket, a file, a pipe. The question is: how do you describe where those bytes live in memory?</p>
</div>
<div class="paragraph">
<p>The obvious answer is a pointer and a size. And for a single contiguous buffer, that works. But real I/O is rarely that tidy. An HTTP response has headers in one buffer and a body in another. A message might be assembled from a protocol header, a payload, and a checksum&#8212;&#8203;each produced by different parts of your code, each sitting in its own memory. The operating system even supports scatter/gather I/O specifically to handle this: a single system call that reads into or writes from <em>multiple</em> non-contiguous buffers.</p>
</div>
<div class="paragraph">
<p>Capy&#8217;s buffer model is designed for this reality. Instead of forcing you to copy data into a single contiguous allocation, Capy uses <em>buffer sequences</em>--lightweight, zero-copy abstractions that let you describe any arrangement of memory and pass it directly to the OS. The design is concept-driven, meaning the compiler verifies correctness at compile time with no runtime overhead.</p>
</div>
<div class="paragraph">
<p>This section covers everything you need to work with memory in Capy&#8217;s I/O model. You will learn the fundamental buffer types, how to compose them into sequences for scatter/gather I/O, and how they map to operating system primitives. You will also meet the algorithms that manipulate buffer data and the dynamic buffer abstractions that grow as data arrives. Understanding buffers is essential for everything that follows&#8212;&#8203;streams, I/O operations, and protocol implementations all build on the abstractions introduced here.</p>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/5.buffers/5.intro.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="../4.coroutines/4g.allocators.html">Frame Allocators</a></span>
<span class="next"><a href="5a.overview.html">Why Concepts, Not Spans</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,670 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Why Concepts, Not Spans :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/5.buffers/5a.overview.html">
<link rel="prev" href="5.intro.html">
<link rel="next" href="5b.types.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../4.coroutines/4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="5.intro.html">Buffer Sequences</a></li>
<li><a href="5a.overview.html">Why Concepts, Not Spans</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="5.intro.html">
<span class="material-symbols-outlined" title="Previous: Buffer Sequences">arrow_back</span>
</a>
<a accesskey="u" href="5.intro.html">
<span class="material-symbols-outlined" title="Up: Buffer Sequences">arrow_upward</span>
</a>
<a accesskey="n" href="5b.types.html">
<span class="material-symbols-outlined" title="Next: Buffer Types">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Why Concepts, Not Spans</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section explains why Capy uses concept-driven buffer sequences instead of <code>std::span</code>, and why this design enables composition without allocation.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Basic C&#43;&#43; experience with memory and pointers</p>
</li>
<li>
<p>Familiarity with C&#43;&#43;20 concepts</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_io_use_case"><a class="anchor" href="#_the_io_use_case"></a>The I/O Use Case</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Buffers exist to interface with operating system I/O. When you read from a socket, write to a file, or transfer data through any I/O channel, you work with contiguous memory regions—addresses and byte counts.</p>
</div>
<div class="paragraph">
<p>The fundamental unit is a <code>(pointer, size)</code> pair. The OS reads bytes from or writes bytes to linear addresses.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_reflexive_answer_span"><a class="anchor" href="#_the_reflexive_answer_span"></a>The Reflexive Answer: span</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The instinctive C&#43;&#43; answer to "how should I represent a buffer?" is <code>std::span&lt;std::byte&gt;</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">void write_data(std::span&lt;std::byte const&gt; data);
void read_data(std::span&lt;std::byte&gt; buffer);</code></pre>
</div>
</div>
<div class="paragraph">
<p>This works for single contiguous buffers. But I/O often involves multiple buffers—a technique called <strong>scatter/gather I/O</strong>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_scattergather_io"><a class="anchor" href="#_scattergather_io"></a>Scatter/Gather I/O</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Consider assembling an HTTP message. The headers are in one buffer; the body is in another. With single-buffer APIs, you must:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Allocate a new buffer large enough for both</p>
</li>
<li>
<p>Copy headers into the new buffer</p>
</li>
<li>
<p>Copy body after headers</p>
</li>
<li>
<p>Send the combined buffer</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>This is wasteful. The data already exists—why copy it?</p>
</div>
<div class="paragraph">
<p>Scatter/gather I/O solves this. Operating systems provide vectored I/O calls (<code>writev</code> on POSIX, scatter/gather with IOCP on Windows) that accept multiple buffers and transfer them as a single logical operation.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_span_reflex_for_multiple_buffers"><a class="anchor" href="#_the_span_reflex_for_multiple_buffers"></a>The Span Reflex for Multiple Buffers</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Extending the span reflex: <code>std::span&lt;std::span&lt;std::byte&gt;&gt;</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">void write_data(std::span&lt;std::span&lt;std::byte const&gt; const&gt; buffers);</code></pre>
</div>
</div>
<div class="paragraph">
<p>This works, but introduces a composition problem.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_composition_problem"><a class="anchor" href="#_the_composition_problem"></a>The Composition Problem</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Suppose you have:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">using HeaderBuffers = std::array&lt;std::span&lt;std::byte const&gt;, 2&gt;; // 2 buffers
using BodyBuffers = std::array&lt;std::span&lt;std::byte const&gt;, 3&gt;; // 3 buffers</code></pre>
</div>
</div>
<div class="paragraph">
<p>To send headers followed by body, you need 5 buffers total. With <code>span&lt;span&lt;byte&gt;&gt;</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">HeaderBuffers headers = /* ... */;
BodyBuffers body = /* ... */;
// To combine, you MUST allocate a new array:
std::array&lt;std::span&lt;std::byte const&gt;, 5&gt; combined;
std::copy(headers.begin(), headers.end(), combined.begin());
std::copy(body.begin(), body.end(), combined.begin() + 2);
write_data(combined);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Every composition allocates. This leads to:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Overload proliferation—separate functions for single buffer, multiple buffers, common cases</p>
</li>
<li>
<p>Performance overhead—allocation on every composition</p>
</li>
<li>
<p>Boilerplate—manual copying everywhere</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_concept_driven_alternative"><a class="anchor" href="#_the_concept_driven_alternative"></a>The Concept-Driven Alternative</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Instead of concrete types, use concepts. Define <code>ConstBufferSequence</code> as "any type that can produce a sequence of buffers":</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">template&lt;ConstBufferSequence Buffers&gt;
void write_data(Buffers const&amp; buffers);</code></pre>
</div>
</div>
<div class="paragraph">
<p>This single signature accepts:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A single <code>const_buffer</code></p>
</li>
<li>
<p>A <code>span&lt;const_buffer&gt;</code></p>
</li>
<li>
<p>A <code>vector&lt;const_buffer&gt;</code></p>
</li>
<li>
<p>A <code>string_view</code> (converts to single buffer)</p>
</li>
<li>
<p>A custom composite type</p>
</li>
<li>
<p><strong>Any composition of the above—without allocation</strong></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_zero_allocation_composition"><a class="anchor" href="#_zero_allocation_composition"></a>Zero-Allocation Composition</h2>
<div class="sectionbody">
<div class="paragraph">
<p>With concepts, composition creates views, not copies:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">HeaderBuffers headers = /* ... */;
BodyBuffers body = /* ... */;
// cat() creates a view that iterates both sequences
auto combined = cat(headers, body); // No allocation!
write_data(combined); // Works because combined satisfies ConstBufferSequence</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>cat</code> function returns a lightweight object that, when iterated, first yields buffers from <code>headers</code>, then from <code>body</code>. The buffers themselves are not copied—only iterators are composed.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_stl_parallel"><a class="anchor" href="#_stl_parallel"></a>STL Parallel</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This design follows Stepanov&#8217;s insight from the STL: algorithms parameterized on concepts (iterators), not concrete types (containers), enable composition that concrete types forbid.</p>
</div>
<div class="paragraph">
<p>The span reflex is a regression from thirty years of generic programming. Concepts restore the compositional power that concrete types lack.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_middle_ground"><a class="anchor" href="#_the_middle_ground"></a>The Middle Ground</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Concepts provide flexibility at user-facing APIs. But at type-erasure boundaries—virtual functions, library boundaries—concrete types are necessary.</p>
</div>
<div class="paragraph">
<p>Capy&#8217;s approach:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>User-facing APIs</strong> — Accept concepts for maximum flexibility</p>
</li>
<li>
<p><strong>Type-erasure boundaries</strong> — Use concrete spans internally</p>
</li>
<li>
<p><strong>Library handles conversion</strong> — Users get concepts; implementation uses spans</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This gives users the composition benefits of concepts while hiding the concrete types needed for virtual dispatch.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_why_not_stdbyte"><a class="anchor" href="#_why_not_stdbyte"></a>Why Not std::byte?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Even <code>std::byte</code> imposes a semantic opinion. POSIX uses <code>void*</code> for semantic neutrality—"raw memory, I move bytes without opining on contents."</p>
</div>
<div class="paragraph">
<p>But <code>span&lt;void&gt;</code> doesn&#8217;t compile—C&#43;&#43; can&#8217;t express type-agnostic buffer abstraction with <code>span</code>.</p>
</div>
<div class="paragraph">
<p>Capy provides <code>const_buffer</code> and <code>mutable_buffer</code> as semantically neutral buffer types. They have known layout compatible with OS structures (<code>iovec</code>, <code>WSABUF</code>) without imposing <code>std::byte</code> semantics.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_summary"><a class="anchor" href="#_summary"></a>Summary</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The reflexive <code>span&lt;span&lt;byte&gt;&gt;</code> approach:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Forces allocation on every composition</p>
</li>
<li>
<p>Leads to overload proliferation</p>
</li>
<li>
<p>Loses the compositional power of generic programming</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The concept-driven approach:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Enables zero-allocation composition</p>
</li>
<li>
<p>Provides a single signature that accepts anything buffer-like</p>
</li>
<li>
<p>Follows proven STL design principles</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Continue to <a href="5b.types.html" class="xref page">Buffer Types</a> to learn about <code>const_buffer</code> and <code>mutable_buffer</code>.</p>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/5.buffers/5a.overview.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="5.intro.html">Buffer Sequences</a></span>
<span class="next"><a href="5b.types.html">Buffer Types</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,657 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Buffer Types :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/5.buffers/5b.types.html">
<link rel="prev" href="5a.overview.html">
<link rel="next" href="5c.sequences.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../4.coroutines/4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="5b.types.html">Buffer Types</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="5.intro.html">Buffer Sequences</a></li>
<li><a href="5b.types.html">Buffer Types</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="5a.overview.html">
<span class="material-symbols-outlined" title="Previous: Why Concepts, Not Spans">arrow_back</span>
</a>
<a accesskey="u" href="5.intro.html">
<span class="material-symbols-outlined" title="Up: Buffer Sequences">arrow_upward</span>
</a>
<a accesskey="n" href="5c.sequences.html">
<span class="material-symbols-outlined" title="Next: Buffer Sequences">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Buffer Types</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section introduces Capy&#8217;s fundamental buffer types: <code>const_buffer</code> and <code>mutable_buffer</code>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Completed <a href="5a.overview.html" class="xref page">Why Concepts, Not Spans</a></p>
</li>
<li>
<p>Understanding of why concept-driven buffers enable composition</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_why_not_stdbyte"><a class="anchor" href="#_why_not_stdbyte"></a>Why Not std::byte?</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>std::byte</code> imposes a semantic opinion. It says "this is raw bytes"—but that is itself an opinion about the data&#8217;s nature.</p>
</div>
<div class="paragraph">
<p>POSIX uses <code>void*</code> for buffers. This expresses semantic neutrality: "I move memory without opining on what it contains." The OS doesn&#8217;t care if the bytes represent text, integers, or compressed data—it moves them.</p>
</div>
<div class="paragraph">
<p>But <code>std::span&lt;void&gt;</code> doesn&#8217;t compile. C&#43;&#43; can&#8217;t express a type-agnostic buffer abstraction using <code>span</code>.</p>
</div>
<div class="paragraph">
<p>Capy provides <code>const_buffer</code> and <code>mutable_buffer</code> as semantically neutral buffer types with known layout.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_const_buffer"><a class="anchor" href="#_const_buffer"></a>const_buffer</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>const_buffer</code> represents a contiguous region of read-only memory:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">class const_buffer
{
public:
const_buffer() = default;
const_buffer(void const* data, std::size_t size) noexcept;
const_buffer(mutable_buffer const&amp; b) noexcept; // Implicit conversion
void const* data() const noexcept;
std::size_t size() const noexcept;
const_buffer&amp; operator+=(std::size_t n) noexcept; // Remove prefix
};</code></pre>
</div>
</div>
<div class="sect2">
<h3 id="_construction"><a class="anchor" href="#_construction"></a>Construction</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">// From pointer and size
char data[] = "hello";
const_buffer buf(data, 5);
// From mutable_buffer (implicit)
mutable_buffer mbuf(data, 5);
const_buffer cbuf = mbuf; // OK: mutable -&gt; const</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_accessors"><a class="anchor" href="#_accessors"></a>Accessors</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">const_buffer buf(data, 5);
void const* ptr = buf.data(); // Pointer to first byte
std::size_t len = buf.size(); // Number of bytes</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_prefix_removal"><a class="anchor" href="#_prefix_removal"></a>Prefix Removal</h3>
<div class="paragraph">
<p>The <code>+=</code> operator removes bytes from the front of the buffer:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">const_buffer buf(data, 10);
buf += 3; // Remove first 3 bytes
// buf.data() now points 3 bytes later
// buf.size() is now 7</code></pre>
</div>
</div>
<div class="paragraph">
<p>This is useful when processing a buffer incrementally.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_mutable_buffer"><a class="anchor" href="#_mutable_buffer"></a>mutable_buffer</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>mutable_buffer</code> represents a contiguous region of writable memory:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">class mutable_buffer
{
public:
mutable_buffer() = default;
mutable_buffer(void* data, std::size_t size) noexcept;
void* data() const noexcept;
std::size_t size() const noexcept;
mutable_buffer&amp; operator+=(std::size_t n) noexcept;
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>The interface mirrors <code>const_buffer</code>, but <code>data()</code> returns non-const <code>void*</code>.</p>
</div>
<div class="sect2">
<h3 id="_conversion"><a class="anchor" href="#_conversion"></a>Conversion</h3>
<div class="paragraph">
<p><code>mutable_buffer</code> implicitly converts to <code>const_buffer</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">void process(const_buffer buf);
mutable_buffer mbuf(data, size);
process(mbuf); // OK: implicit conversion</code></pre>
</div>
</div>
<div class="paragraph">
<p>The reverse is not allowed—you cannot implicitly convert <code>const_buffer</code> to <code>mutable_buffer</code>.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_make_buffer"><a class="anchor" href="#_make_buffer"></a>make_buffer</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <code>make_buffer</code> function creates buffers from various sources:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;boost/capy/buffers/make_buffer.hpp&gt;
// From pointer and size
auto buf = make_buffer(ptr, size);
// From C array
char arr[10];
auto buf = make_buffer(arr);
// From std::array
std::array&lt;char, 10&gt; arr;
auto buf = make_buffer(arr);
// From std::vector
std::vector&lt;char&gt; vec(100);
auto buf = make_buffer(vec);
// From std::string
std::string str = "hello";
auto buf = make_buffer(str);
// From std::string_view
std::string_view sv = "hello";
auto buf = make_buffer(sv);</code></pre>
</div>
</div>
<div class="paragraph">
<p>The returned buffer type depends on constness:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Non-const containers → <code>mutable_buffer</code></p>
</li>
<li>
<p>Const containers, <code>string_view</code><code>const_buffer</code></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_layout_compatibility"><a class="anchor" href="#_layout_compatibility"></a>Layout Compatibility</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>const_buffer</code> and <code>mutable_buffer</code> have the same memory layout as OS buffer structures:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>POSIX: <code>struct iovec { void* iov_base; size_t iov_len; }</code></p>
</li>
<li>
<p>Windows: <code>struct WSABUF { ULONG len; CHAR* buf; }</code> (note: different order)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This means conversion to OS structures is efficient—often just a reinterpret_cast for arrays of buffers.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_single_buffers_as_sequences"><a class="anchor" href="#_single_buffers_as_sequences"></a>Single Buffers as Sequences</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A single buffer is a degenerate sequence—a sequence with one element. The <code>ConstBufferSequence</code> and <code>MutableBufferSequence</code> concepts recognize this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">template&lt;ConstBufferSequence Buffers&gt;
void write_data(Buffers const&amp; buffers);
// All of these work:
write_data(make_buffer("hello")); // Single buffer
write_data(std::array{buf1, buf2, buf3}); // Multiple buffers
write_data(my_composite); // Custom sequence</code></pre>
</div>
</div>
<div class="paragraph">
<p>The library provides <code>begin()</code> and <code>end()</code> functions that work uniformly:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">const_buffer single;
auto it = begin(single); // Returns pointer to single
auto e = end(single); // Returns pointer past single
std::array&lt;const_buffer, 3&gt; multi;
auto it = begin(multi); // Returns multi.begin()
auto e = end(multi); // Returns multi.end()</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_reference"><a class="anchor" href="#_reference"></a>Reference</h2>
<div class="sectionbody">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 75%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Header</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/buffers.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Core buffer types and concepts</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/buffers/make_buffer.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Buffer creation utilities</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>You have now learned about <code>const_buffer</code> and <code>mutable_buffer</code>. Continue to <a href="5c.sequences.html" class="xref page">Buffer Sequences</a> to understand how these types compose into sequences.</p>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/5.buffers/5b.types.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="5a.overview.html">Why Concepts, Not Spans</a></span>
<span class="next"><a href="5c.sequences.html">Buffer Sequences</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,650 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
<script>document.documentElement.classList.add('fonts-loading');</script>
<link rel="preload" href="../../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="../../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<script>
(function() {
'use strict';
var revealed = false;
var reveal = function() {
if (revealed) return;
revealed = true;
document.documentElement.classList.remove('fonts-loading');
};
setTimeout(reveal, 3000);
if (!('FontFace' in window) || !('fonts' in document)) {
setTimeout(reveal, 100);
return;
}
var uiRoot = '../../_';
var fonts = [
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay.woff2',
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Noto Sans',
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
},
{
family: 'Monaspace Neon',
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
descriptors: { style: 'normal', weight: '400' }
},
{
family: 'Monaspace Xenon',
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
descriptors: { style: 'italic', weight: '400' }
}
];
var loadPromises = fonts.map(function(f) {
try {
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
return face.load().then(function(loaded) {
document.fonts.add(loaded);
return loaded;
}).catch(function() {
return null;
});
} catch (e) {
return Promise.resolve(null);
}
});
Promise.all(loadPromises)
.then(function() {
return document.fonts.ready;
})
.then(reveal)
.catch(reveal);
})();
</script> <title>Buffer Sequences :: Boost Libraries Documentation</title>
<link rel="canonical" href="https://antora.cppalliance.org/develop/lib/doc/capy/5.buffers/5c.sequences.html">
<link rel="prev" href="5b.types.html">
<link rel="next" href="5d.system-io.html">
<meta name="generator" content="Antora 3.1.14">
<link rel="stylesheet" href="../../_/css/boostlook.css">
<link rel="stylesheet" href="../../_/css/site.css">
<link rel="stylesheet" href="../../_/css/vendor/tabs.css">
<script>
(function() {
if (window.self !== window.top) return;
var theme = localStorage.getItem('antora-theme');
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
}
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
</script>
<script>var uiRootPath = '../../_'</script>
<link rel="icon" href="../../_/img/favicons/favicon.ico" type="image/x-icon">
<!-- Favicon configuration -->
<link rel="apple-touch-icon" sizes="180x180" href="../../_/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../_/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../_/img/favicons/favicon-16x16.png">
<link rel="manifest" href="../../_/img/favicons/site.webmanifest">
<link rel="shortcut icon" href="../../_/img/favicons/favicon.ico">
</head>
<body class="article toc2 toc-left">
<div class="boostlook">
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
<div id="toc" class="nav-container toc2" data-component="capy" data-version="">
<aside class="nav">
<button class="nav-close"></button>
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<div class="title-row">
<h3 class="title"><a href="../index.html">Boost.Capy</a></h3>
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
<i class="fas fa-sun theme-icon-light"></i>
<i class="fas fa-moon theme-icon-dark"></i>
</button> </div>
<ul class="nav-list">
<ul class="nav-list">
<li class="" data-depth="1">
<a class="nav-link" href="../index.html">Introduction</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../why-capy.html">Why Capy?</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../quick-start.html">Quick Start</a>
</li>
<li class="" data-depth="1">
<a class="nav-link" href="../2.cpp20-coroutines/2.intro.html">Introduction To C&#43;&#43;20 Coroutines</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2b.syntax.html">Part II: C&#43;&#43;20 Syntax</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2c.machinery.html">Part III: Coroutine Machinery</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../2.cpp20-coroutines/2d.advanced.html">Part IV: Advanced Topics</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../3.concurrency/3.intro.html">Introduction to Concurrency</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3a.foundations.html">Part I: Foundations</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3b.synchronization.html">Part II: Synchronization</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3c.advanced.html">Part III: Advanced Primitives</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../3.concurrency/3d.patterns.html">Part IV: Communication &amp; Patterns</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../4.coroutines/4.intro.html">Coroutines in Capy</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4a.tasks.html">The task Type</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4b.launching.html">Launching Coroutines</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4c.executors.html">Executors and Execution Contexts</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4d.io-awaitable.html">The IoAwaitable Protocol</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4e.cancellation.html">Stop Tokens and Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4f.composition.html">Concurrent Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../4.coroutines/4g.allocators.html">Frame Allocators</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="5.intro.html">Buffer Sequences</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="5a.overview.html">Why Concepts, Not Spans</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5b.types.html">Buffer Types</a>
</li>
<li class=" is-current-page" data-depth="2">
<a class="nav-link" href="5c.sequences.html">Buffer Sequences</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5d.system-io.html">System I/O Integration</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5e.algorithms.html">Buffer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="5f.dynamic.html">Dynamic Buffers</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../6.streams/6.intro.html">Stream Concepts</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6a.overview.html">Overview</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6b.streams.html">Streams (Partial I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6c.sources-sinks.html">Sources and Sinks (Complete I/O)</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6d.buffer-concepts.html">Buffer Sources and Sinks</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6e.algorithms.html">Transfer Algorithms</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../6.streams/6f.isolation.html">Physical Isolation</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../7.examples/7.intro.html">Example Programs</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7a.hello-task.html">Hello Task</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7b.producer-consumer.html">Producer-Consumer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7c.buffer-composition.html">Buffer Composition</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7d.mock-stream-testing.html">Mock Stream Testing</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7e.type-erased-echo.html">Type-Erased Echo</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7f.timeout-cancellation.html">Timeout with Cancellation</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7g.parallel-fetch.html">Parallel Fetch</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7h.custom-dynamic-buffer.html">Custom Dynamic Buffer</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7i.echo-server-corosio.html">Echo Server with Corosio</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../7.examples/7j.stream-pipeline.html">Stream Pipeline</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../8.design/8.intro.html">Design</a>
</li>
<ul class="nav-list">
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8a.CapyLayering.html">Layered Abstractions</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8b.Separation.html">Why Capy Is Separate</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8c.ReadStream.html">ReadStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8d.ReadSource.html">ReadSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8e.BufferSource.html">BufferSource</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8f.WriteStream.html">WriteStream</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8g.WriteSink.html">WriteSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8h.BufferSink.html">BufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8i.TypeEraseAwaitable.html">Type-Erasing Awaitables</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8j.any_buffer_sink.html">AnyBufferSink</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8k.Executor.html">Executor</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8l.RunApi.html">Run API</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8m.WhyNotCobalt.html">Why Not Cobalt?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8n.WhyNotCobaltConcepts.html">Why Not Cobalt Concepts?</a>
</li>
<li class="" data-depth="2">
<a class="nav-link" href="../8.design/8o.WhyNotTMC.html">Why Not TooManyCooks?</a>
</li>
</ul>
<li class="" data-depth="1">
<a class="nav-link" href="../reference/boost/capy.html">Reference</a>
</li>
</ul>
</ul>
</nav>
</div>
</div>
</aside>
</div>
</div> <div id="content">
<article class="doc max-width-reset">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li>
<a href="../index.html" aria-label="Home: Boost.Capy">
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
</a>
</li>
<li><a href="5.intro.html">Buffer Sequences</a></li>
<li><a href="5c.sequences.html">Buffer Sequences</a></li>
</ul>
</nav>
<div class="spirit-nav">
<a accesskey="p" href="5b.types.html">
<span class="material-symbols-outlined" title="Previous: Buffer Types">arrow_back</span>
</a>
<a accesskey="u" href="5.intro.html">
<span class="material-symbols-outlined" title="Up: Buffer Sequences">arrow_upward</span>
</a>
<a accesskey="n" href="5d.system-io.html">
<span class="material-symbols-outlined" title="Next: System I/O Integration">arrow_forward</span>
</a>
</div></div>
<h1 class="page">Buffer Sequences</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This section explains buffer sequences—the concept that enables zero-allocation composition of buffers.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites"><a class="anchor" href="#_prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Completed <a href="5b.types.html" class="xref page">Buffer Types</a></p>
</li>
<li>
<p>Understanding of <code>const_buffer</code> and <code>mutable_buffer</code></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_what_is_a_buffer_sequence"><a class="anchor" href="#_what_is_a_buffer_sequence"></a>What Is a Buffer Sequence?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A <strong>buffer sequence</strong> is any type that can produce an iteration of buffers. Formally:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A single buffer (like <code>const_buffer</code>) is a sequence of one element</p>
</li>
<li>
<p>A range of buffers (like <code>vector&lt;const_buffer&gt;</code>) is a multi-element sequence</p>
</li>
<li>
<p>Any bidirectional range with buffer-convertible values qualifies</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_concepts"><a class="anchor" href="#_the_concepts"></a>The Concepts</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_constbuffersequence"><a class="anchor" href="#_constbuffersequence"></a>ConstBufferSequence</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">template&lt;typename T&gt;
concept ConstBufferSequence =
std::is_convertible_v&lt;T, const_buffer&gt; || (
std::ranges::bidirectional_range&lt;T&gt; &amp;&amp;
std::is_convertible_v&lt;std::ranges::range_value_t&lt;T&gt;, const_buffer&gt;);</code></pre>
</div>
</div>
<div class="paragraph">
<p>A type satisfies <code>ConstBufferSequence</code> if:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>It converts to <code>const_buffer</code> directly (single buffer), OR</p>
</li>
<li>
<p>It is a bidirectional range whose elements convert to <code>const_buffer</code></p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_mutablebuffersequence"><a class="anchor" href="#_mutablebuffersequence"></a>MutableBufferSequence</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">template&lt;typename T&gt;
concept MutableBufferSequence =
std::is_convertible_v&lt;T, mutable_buffer&gt; || (
std::ranges::bidirectional_range&lt;T&gt; &amp;&amp;
std::is_convertible_v&lt;std::ranges::range_value_t&lt;T&gt;, mutable_buffer&gt;);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Same pattern, but for <code>mutable_buffer</code>.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_satisfying_the_concepts"><a class="anchor" href="#_satisfying_the_concepts"></a>Satisfying the Concepts</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Many common types satisfy these concepts:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">// Single buffers
const_buffer cb; // ConstBufferSequence
mutable_buffer mb; // MutableBufferSequence (and ConstBufferSequence)
// Standard containers of buffers
std::vector&lt;const_buffer&gt; v; // ConstBufferSequence
std::array&lt;mutable_buffer, 3&gt; a; // MutableBufferSequence
// String types (convert to single buffer)
std::string str; // ConstBufferSequence (via make_buffer)
std::string_view sv; // ConstBufferSequence</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_heterogeneous_composition"><a class="anchor" href="#_heterogeneous_composition"></a>Heterogeneous Composition</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Because the concept accepts anything convertible to buffer, you can mix types:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">template&lt;ConstBufferSequence Buffers&gt;
void send(Buffers const&amp; bufs);
// All of these work:
send(make_buffer("Hello")); // string literal
send(std::string_view{"Hello"}); // string_view
send(std::array{buf1, buf2}); // array of buffers
send(my_custom_buffer_sequence); // custom type</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_iterating_buffer_sequences"><a class="anchor" href="#_iterating_buffer_sequences"></a>Iterating Buffer Sequences</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Use <code>begin()</code> and <code>end()</code> from <code>&lt;boost/capy/buffers.hpp&gt;</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">template&lt;ConstBufferSequence Buffers&gt;
void process(Buffers const&amp; bufs)
{
for (auto it = begin(bufs); it != end(bufs); ++it)
{
const_buffer buf = *it;
// Process buf.data(), buf.size()
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>These functions handle both single buffers (returning pointer-to-self) and ranges (returning standard iterators).</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_consuming_buffers"><a class="anchor" href="#_consuming_buffers"></a>consuming_buffers</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When transferring data incrementally, <code>consuming_buffers</code> tracks progress:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include &lt;boost/capy/buffers/consuming_buffers.hpp&gt;
template&lt;MutableBufferSequence Buffers&gt;
task&lt;std::size_t&gt; read_all(Stream&amp; stream, Buffers buffers)
{
consuming_buffers&lt;Buffers&gt; remaining(buffers);
std::size_t total = 0;
while (buffer_size(remaining) &gt; 0)
{
auto [ec, n] = co_await stream.read_some(remaining);
if (ec.failed())
break;
remaining.consume(n);
total += n;
}
co_return total;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>consuming_buffers</code> wraps a buffer sequence and provides:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>consume(n)</code> — Mark <code>n</code> bytes as consumed (remove from front)</p>
</li>
<li>
<p>Iteration over unconsumed buffers</p>
</li>
<li>
<p><code>buffer_size()</code> of remaining bytes</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_zero_allocation_composition"><a class="anchor" href="#_zero_allocation_composition"></a>Zero-Allocation Composition</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <code>cat()</code> function composes buffer sequences without allocation:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">auto headers = std::array{header_buf1, header_buf2};
auto body = body_buffer;
auto combined = cat(headers, body); // No allocation
// combined satisfies ConstBufferSequence
// Iteration yields: header_buf1, header_buf2, body_buffer</code></pre>
</div>
</div>
<div class="paragraph">
<p>The returned object stores references (or small copies for single buffers) and iterates through the composed sequence on demand.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_why_bidirectional"><a class="anchor" href="#_why_bidirectional"></a>Why Bidirectional?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The concepts require bidirectional ranges (not just forward ranges) for two reasons:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Some algorithms traverse buffers backwards</p>
</li>
<li>
<p><code>consuming_buffers</code> needs to adjust the first buffer&#8217;s start position</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>If your custom buffer sequence only provides forward iteration, wrap it in a type that provides bidirectional access.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_reference"><a class="anchor" href="#_reference"></a>Reference</h2>
<div class="sectionbody">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 75%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Header</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/buffers.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Concepts and iteration functions</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>&lt;boost/capy/buffers/consuming_buffers.hpp&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Incremental consumption wrapper</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>You have now learned how buffer sequences enable zero-allocation composition. Continue to <a href="5d.system-io.html" class="xref page">System I/O Integration</a> to see how buffer sequences interface with operating system I/O.</p>
</div>
</div>
</div>
<div class="edit-this-page">
<a href="https://github.com/cppalliance/capy/edit/develop/doc/modules/ROOT/pages/5.buffers/5c.sequences.adoc">Edit this Page</a>
</div>
<nav class="pagination">
<span class="prev"><a href="5b.types.html">Buffer Types</a></span>
<span class="next"><a href="5d.system-io.html">System I/O Integration</a></span>
</nav>
</article>
</div>
<div id="footer">
<script id="site-script" src="../../_/js/site.js" data-ui-root-path="../../_"></script>
<script async src="../../_/js/vendor/highlight.js"></script>
<script async src="../../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
</div>
</div>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More