155 Commits

Author SHA1 Message Date
julioest
fc974957e2 feat: add changelog section to preview landing page 2026-02-24 13:07:52 -05:00
julioest
33ce117d70 feat: add surface-weak and stroke-weak tokens for note admonition 2026-02-24 07:50:27 -05:00
julioest
c897fbe5ed fix: add missing vertical spacing after paragraphs before code blocks and lists 2026-02-24 07:18:02 -05:00
julioest
a5af8c95cc fix: align spacing tokens with Figma and prevent link-row word break 2026-02-24 06:09:49 -05:00
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
Julio Estrada
538540cdc9 revert changes to boostlook.css, move Tino design to separate file #93
- add boostlook_tino.css design system
- revert boostlook.css to previous version
- remove boostlook_old.css backup
2025-03-13 17:15:43 -04:00
Julio Estrada
2f6553ba31 ci(workflow): update sync workflow branch trigger from develop to master 2025-03-07 18:16:55 -05:00
wdm-ih
adec6006ce update boostlook.css to new design system
remove high level styles

updated styles for common components; set basic layout margins;

antora and asciidoc templates desktop

antora and asciidoc mobile

commented unused legacy css variables

fixed styles for links in code blocks

Quickbook template adaptation

removed unused css vars

templates specific adjustments; syntax colors
2025-03-05 18:09:45 +02:00
Julio Estrada
db19639793 fix(css): ensure consistent toc behavior across breakpoints 2025-03-04 18:52:33 -05:00
Chrissy Wainwright
ee40a557f9 fix z-index on spirit nav #406
the spirit nav should be clickable when the h2 takes up the same space
2025-02-21 09:48:11 -06:00
Julio Estrada
fab289a8fb backup boostlook.css file 2025-02-19 12:37:26 -05:00
Chrissy Wainwright
ae8eff4cfa maintain root font size above 1024px 2025-02-17 09:34:07 -06:00
Chrissy Wainwright
6ac3315c1e revert vertical scrollbars to always display
* make wider
* keep rounded corners
2025-02-17 09:33:54 -06:00
Chrissy Wainwright
aaf7928ae1 550 weight for more #toc styles 2025-02-06 09:02:05 -06:00
Chrissy Wainwright
1996d2e5cd adjust TOC colors/bolding 2025-02-06 09:02:05 -06:00
Chrissy Wainwright
60ea4e15ea Scrollbar consistency
* unset scrollbar-color and scrollbar-width. This has an unintended
  effect of displaying the arrow buttons in Webkit on PC
* display scrollbars as very thin
* update all scrollbars in boostlook to behave the same way:
  thin and only show up on hover
2025-01-27 11:35:35 -06:00
Julio Estrada
1d8f100e27 add relative positioning to headings 2025-01-23 15:52:42 -05:00
Chrissy Wainwright
f2912dae60 Update how horizontal scrollbars work for code and tables
For consistency across browsers and systems, set the overflow-x to auto, but using colors that match the background of the code block or table, so the scrollbar isn’t initially visible. On hover, the colors will change to the defined scrollbar colors. Note they do still display differently depending on each user’s systems settings, based on if they use classic or overlay scrollbars
Also moved scrollbar-related code to that section of the CSS file
2025-01-23 11:28:40 -06:00
Chrissy Wainwright
edae038a12 Final round CSS refactor
* make sure comments at top match file and template structures
* move styling around to be in the correct sections, with other similar styles
2025-01-17 11:57:56 -06:00
Chrissy Wainwright
635523765b fixed toolbar for mobile 2025-01-10 17:12:00 -06:00
Chrissy Wainwright
4691e12a97 display spirit nav on .qbk docs
* fix placement so spirit nav is always in upper right
* hide footer spirit nav, since it wasn't visible before this change
2025-01-10 17:12:00 -06:00
Chrissy Wainwright
e4bbe2c988 CSS refactoring
* remove duplicate heading declaration
* move #libraryReadMe selectors to single section
* use numerical value for font-weight instead of 'normal'
* define --bl-secondary-color
* work on combining duplicated selectors
* move scrollbar styles to single section
* move spriti nav styles to single section
2025-01-10 16:57:21 -06:00
Julio Estrada
2d1ce0543b feat: enhance boostlook.css with structural updates, theming, and README styles
- correct font size and variable references
- add missing theme variables and improve typography
- add styles for Library README section
- improve structural and styling updates across components
2025-01-08 17:19:38 -05:00
Julio Estrada
8e0507c040 feat: add asciidoc live preview (#27)
- add live preview functionality for local doc development
- document setup prerequisites and usage in README
- include basic troubleshooting guide
- run pre-commit on all files
2024-12-24 18:12:55 -05:00
Julio Estrada
0d189f8dba refactor: enhance scrollbar UX and overflow handling
enhance scrollbar styles:
- hide scrollbars for iframes and apply custom scrollbar styles
- ensure nav/toc and content areas are scrollable with proper styling
- remove horizontal scrollbars in code blocks
- fix template-specific scroll styling and behavior
2024-12-21 09:49:59 -05:00
Chrissy Wainwright
8c8b17b371 further style fixes 2024-12-19 08:14:28 -06:00
Chrissy Wainwright
ac9339031c Bring styles over from boostbook; makes styling consistent across doc types 2024-12-19 08:14:28 -06:00
Chrissy Wainwright
898d3194db various adjustments for links, code, and headings
* remove border radius on code blocks
* update/fix hover styling for links - change color and underline
* bg color for code blocks
* reduce spacing on Antora TOC links
* reduce size of h1 and h2
* remove spacing between .qbk TOC sections
* spirit nav hover styles
2024-12-17 08:54:23 -06:00
Julio Estrada
f8c7e6c87c chore: update boostlook.css sync workflow, fix boostlook.rb syntax 2024-12-17 09:12:45 -05:00
Julio Estrada
608c10de80 Update font-weight for Noto Sans Display in boostlook.css 2024-12-13 17:35:47 -05:00
Chrissy Wainwright
35446e1a34 libraryReadMe style fixes for consistency
* margin beneath lists
* heading font sizes to match Antora
2024-12-13 09:05:41 -06:00
Julio C. Estrada
78a00e206d refactor: update boostlook.css library readme styles (#62) 2024-12-11 18:05:44 -05:00
Julio C. Estrada
62a0a7e179 hide scrollbars (#61) 2024-12-11 16:01:32 -05:00
Rob Beeston
3541dca9b5 Merge pull request #60 from cdw9/54_headings_toc 2024-12-10 15:26:55 -08:00
Chrissy Wainwright
4771a0aa9d heading and TOC styles for consistency
* adjust size and spacing for headings to match Antora
* TOC style adjustments - less bold headings
* code size and color within headings and TOC
2024-12-10 15:16:18 -06:00
Chrissy Wainwright
b3355ac246 Merge pull request #59 from cdw9/54_code
adjustments for code styles, table headers
2024-12-09 15:22:33 -06:00
Chrissy Wainwright
eada473564 code style adjustments 2024-12-09 15:21:14 -06:00
Chrissy Wainwright
57721be356 adjustments for code styles, table headers 2024-12-09 15:09:09 -06:00
Chrissy Wainwright
82821acb50 Merge pull request #57 from cdw9/1521_code_links
fix link colors
2024-12-05 16:01:39 -06:00
Chrissy Wainwright
0260bc0e6e lighter font weight for code 2024-12-05 15:29:45 -06:00
Chrissy Wainwright
8a925d39ad lighten font weight on code 2024-12-05 13:29:48 -06:00
Chrissy Wainwright
084de82b16 fix link colors
* set the global link hover color to the same value as --bl-primary-color
* fix link styles for links that are also code, so it is clear they are links
2024-12-05 12:51:13 -06:00
Chrissy Wainwright
ec5e02c410 Merge pull request #55 from cdw9/cdw9/54_qbk
styling fixes for quickbook docs
2024-12-03 19:01:52 -06:00
Chrissy Wainwright
de37aec7ab display qbk spirit-nav like antora 2024-12-03 17:09:33 -06:00
Chrissy Wainwright
36c49442a9 adjust alignment
* left align tables, toc, and notes
* move heading up to line up with nav icons
2024-12-03 14:41:58 -06:00
Chrissy Wainwright
d05b628e9e styling fixes for quickbook docs 2024-12-03 10:52:48 -06:00
Julio C. Estrada
1b1d71001a replace gh token with personal access token (#53) 2024-11-26 06:51:15 -05:00
Julio C. Estrada
c979b040a7 add workflow_dispatch to allow manual workflow runs (#52) 2024-11-25 21:54:00 -05:00
Julio C. Estrada
27f02db77b rename sync-boostlook-css workflow and configure GH_TOKEN for v2-docs workflows (#51) 2024-11-25 21:33:44 -05:00
Chrissy Wainwright
5c6f1f5581 fix mobile TOC and remove extra scrollbar (#50)
* fix mobile TOC and remove extra scrollbar

* remove extra space when TOC is collapsed
* remove extra scrollbar from content area

* display TOC as static when it needs to be
2024-11-25 20:49:40 -05:00
Julio Estrada
3487d92ec4 rename and update gha workflow to sync boostlook.css across repos
- renamed workflow file from update-website-v2.yml to sync-boostlook-css.yml
- simplified commit process to push changes directly to develop branch if updates are detected
- added steps to trigger ui-release and publish workflows in website-v2-docs repository
- ensured pre-commit hooks are run before committing updates

fixes #44
2024-11-25 14:32:21 -05:00
Julio Estrada
c28cc7213c enhance boostlook layout and fix toc display on mobile
- added padding and border-radius to #header, #content, and #footer
- refactored TOC with fixed position and overflow
- implemented conditional footer padding using :has()
- added media query for responsive border-radius on #content
- fixed TOC not displaying on mobile devices

addresses https://github.com/boostorg/website-v2-docs/issues/359
2024-11-22 15:31:44 -05:00
Chrissy Wainwright
1e8dcf8dad Merge pull request #46 from cdw9/develop
Boostlook styling updates
2024-11-21 17:00:29 -06:00
Chrissy Wainwright
16a37fde6a Boostlook styling updates
* fix inline code styles within colists
* remove letter spacing from h2 headings
* adjust TOC padding to match content area
* fix table headings and borders for dark mode
* display paragraphs within list items as inline (for readmes)
* rounded corners for <pre> and .highlight blocks
* make sure <strong> displays as bold
* consistency for <code> wherever it appears
2024-11-21 13:16:10 -06:00
Rob Beeston
00a5b0e987 Merge pull request #43 from cdw9/develop 2024-11-18 12:40:16 -08:00
Chrissy Wainwright
76e16aea8c prevent h2 border from extending to the left
adjust anchor link vertical positioning next to the heading
2024-11-18 14:27:40 -06:00
Chrissy Wainwright
53cd5a0b03 add scrollbars to wide tables refs #358 2024-11-18 10:00:57 -06:00
Chrissy Wainwright
6d8c6b1bc4 Various adjustments to improve text legibility
* update styles for inline code
  * remove background color, make bold
* update text and link colors for better contrast
* add border radius to boxes (notes and code) to match nav
* update code block padding to give space for copy icon and horizontal scroll
* increase letter spacing on headings
* update TOC spacing
* make <th> same size as rest of the text

refs #40
2024-11-15 11:38:42 -06:00
Julio Estrada
c58e2c230f gha: rename workflow and add repo condition for boostlook.css update 2024-11-14 15:16:23 -05:00
Julio Estrada
1f05284790 gha: update workflow trigger branch to 'develop'
addresses #38
2024-11-13 16:39:11 -05:00
Julio Estrada
21d8b262e8 refactor: refine regex for <body> targeting, adjust CSS for releases page 2024-11-13 15:19:47 -05:00
1079 changed files with 471776 additions and 606 deletions

1
.gitattributes vendored
View File

@@ -1,4 +1,3 @@
* text=auto
*.css text eol=lf

View File

@@ -0,0 +1,72 @@
name: Sync boostlook.css to website-v2 & website-v2-docs
on:
push:
branches: ["develop"]
paths:
- "boostlook.css"
workflow_dispatch:
permissions:
contents: write
jobs:
update-css:
runs-on: ubuntu-latest
if: github.repository == 'boostorg/boostlook'
steps:
- name: Checkout current repository
uses: actions/checkout@v6
- name: Checkout website-v2 repository
uses: actions/checkout@v6
with:
repository: boostorg/website-v2
ref: develop
path: website-v2
token: ${{ secrets.WEBSITE_V2_PAT }}
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.13"
- name: Copy boostlook.css to website-v2
run: |
cp -v boostlook.css website-v2/static/css/boostlook.css
- name: Install pre-commit
if: success()
run: |
pip install pre-commit
- name: Run pre-commit hooks on boostlook.css
if: success()
working-directory: website-v2
run: |
pre-commit run --files static/css/boostlook.css
- name: Commit and push changes to develop branch
if: success()
working-directory: website-v2
env:
GH_TOKEN: ${{ secrets.WEBSITE_V2_PAT }}
run: |
git config user.name "${{ github.actor }}"
git config user.email "${{ github.actor }}@users.noreply.github.com"
git add static/css/boostlook.css
if ! git diff-index --quiet HEAD; then
git commit -m "chore: Update boostlook.css from boostlook repository"
git push origin develop
else
echo "No changes to commit. Skipping commit to develop."
fi
- name: Trigger website-v2-docs ui-release workflow
if: success()
env:
GH_TOKEN: ${{ secrets.WEBSITE_V2_PAT }}
run: |
gh workflow run ui-release.yml --repo boostorg/website-v2-docs --ref develop
- name: Trigger website-v2-docs publish workflow
if: success()
env:
GH_TOKEN: ${{ secrets.WEBSITE_V2_PAT }}
run: |
gh workflow run publish.yml --repo boostorg/website-v2-docs --ref develop

View File

@@ -1,70 +0,0 @@
name: Update boostlook.css in website-v2
on:
push:
branches: [ "master" ]
paths:
- 'boostlook.css'
permissions:
pull-requests: write
jobs:
update-css:
runs-on: ubuntu-latest
steps:
- name: Checkout boostlook repository
uses: actions/checkout@v4
with:
repository: boostorg/boostlook
- name: Checkout website-v2 repository
uses: actions/checkout@v4
with:
repository: boostorg/website-v2
ref: develop
path: website-v2
token: ${{ secrets.WEBSITE_V2_PAT }}
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Copy boostlook.css to website-v2
run: |
cp boostlook.css website-v2/static/css/boostlook.css
- name: Install pre-commit
if: success()
run: |
pip install pre-commit
- name: Run pre-commit hooks on boostlook.css
if: success()
working-directory: website-v2
run: |
pre-commit run --files static/css/boostlook.css
continue-on-error: false
- name: Commit and push changes to a new branch
if: success()
working-directory: website-v2
env:
GH_TOKEN: ${{ secrets.WEBSITE_V2_PAT }}
run: |
git config user.name "${{ github.actor }}"
git config user.email "${{ github.actor }}@users.noreply.github.com"
git add static/css/boostlook.css
if ! git diff-index --quiet HEAD; then
git commit -m "Update boostlook.css from boostlook repository"
branch_name="update-boostlook-css-$(date +'%Y%m%d%H%M%S')"
git checkout -b "$branch_name"
git push origin "$branch_name"
gh pr create --title "Update boostlook.css from boostlook repository" \
--body "Automated PR to update boostlook.css" \
--base develop \
--head "$branch_name"
else
echo "No changes to commit. Skipping PR creation."
fi

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.

View File

@@ -15,3 +15,97 @@ html mp11.html : mp11.adoc
Noto font files are covered under the Open Font License:
https://fonts.google.com/noto/use
## Live Preview for AsciiDoc Documentation
BoostLook includes a **live preview** feature to streamline local development and review of AsciiDoc documentation. This allows for automatic rendering and real-time browser preview of changes made to [`specimen.adoc`](/doc/specimen.adoc) and [`boostlook.css`](/boostlook.css) files.
### Overview
The preview functionality is handled by a Ruby script ([`boostlook_preview.rb`](./boostlook_preview.rb)). This script monitors AsciiDoc, HTML, and CSS files for changes, automatically rebuilding and opening the rendered HTML in your default web browser.
---
### Prerequisites
Ensure the following dependencies are installed:
- **Ruby** (>= 2.7 recommended)
- **Asciidoctor** Install via `gem install asciidoctor`
- **Listen Gem** Install via `gem install listen`
- **Boost.Build (b2)** Required for builds invoked by the script. Ensure it is installed and available in your system's PATH.
---
### Usage and Detailed Steps
1. **Install Ruby and Required Gems**:
- Ensure Ruby is installed on your system. You can check by running:
```bash
ruby -v
```
If Ruby is not installed, follow the instructions on [ruby-lang.org](https://www.ruby-lang.org/en/documentation/installation/) to install it.
- Install Asciidoctor:
```bash
gem install asciidoctor
```
- Install the Listen gem:
```bash
gem install listen
```
2. **Install Boost.Build (b2)**:
- Follow the instructions on the [Boost.Build website](https://boostorg.github.io/build/) to install `b2`.
- Ensure `b2` is available in your system's PATH by running:
```bash
which b2
```
3. **Locate Specimen AsciiDoc File**:
- Place your AsciiDoc files in the `doc` directory. The default file is `doc/specimen.adoc`.
- The default file structure should include:
```
/boostlook
├── doc
│ └── specimen.adoc <--
│ └── ...
├── boostlook.css
└── boostlook_preview.rb
└── boostlook.rb
└── ...
```
4. **Navigate to the project directory**:
```bash
cd /path/to/boostlook
```
5. **Run the preview script**:
- Ensure you're in the root folder
```bash
ruby boostlook_preview.rb
```
6. **Edit and Preview**:
- Edit your AsciiDoc (specimen.adoc) or CSS (boostlook.css) files.
- The script will automatically detect changes and rebuild the documentation.
- Refresh the browser to see changes.
7. **Refresh Your Browser** to view changes.
---
### Troubleshooting
- **Script Not Running**:
- Ensure all prerequisites are installed correctly.
- Check for any error messages in the terminal and resolve them accordingly.
- **Changes Not Reflecting**:
- Ensure the files being edited are within the monitored directories (`doc` and root directory).
- Verify that the browser is refreshing automatically or manually refresh the browser.
- **Boost.Build (b2) Not Found**:
- Ensure `b2` is installed and available in your system's PATH.
- Run `which b2` to verify its availability.

1
_ Symbolic link
View File

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

5037
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

@@ -1,74 +1,75 @@
Asciidoctor::Extensions.register do
postprocessor do
process do |doc, output|
output = output.sub(/<body(.*?)>/, '<body\\1><div class="boostlook">')
output = output.sub(/<\/body>/, "</div></body>")
output = output.sub(/(<div id="toc".*?>)/, '<button id="toggle-toc" title="Show Table of Contents" aria-expanded="false" aria-controls="toc">☰</button>\\1')
output = output.sub(/(<div id="footer".*?>)/, '</div>\\1')
inline_script = <<~SCRIPT
<script>
(function() {
var isVisible = localStorage.getItem('tocVisible') === 'true';
var isPinned = localStorage.getItem('tocPinned') === 'true';
document.documentElement.classList.toggle('toc-visible', isVisible);
document.documentElement.classList.toggle('toc-hidden', !isVisible);
document.documentElement.classList.toggle('toc-pinned', isPinned);
})();
</script>
SCRIPT
output = output.sub(/<\/head>/, "#{inline_script}</head>")
output = output.sub(/(<body[^>]*>)/, '\1<div class="boostlook">')
output = output.sub('</body>', '</div></body>')
# 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>
document.addEventListener("DOMContentLoaded", (event) => {
const tocButton = document.getElementById("toggle-toc");
const toc = document.getElementById("toc");
(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');
let isVisible = localStorage.getItem("tocVisible") === "true";
let isPinned = localStorage.getItem("tocPinned") === "true";
// Comment out toggle functionality since TOC should always be visible
/*
const isPinned = localStorage.getItem('tocPinned') === 'true';
function updateTocVisibility(visible) {
html.classList.toggle("toc-visible", visible);
html.classList.toggle("toc-hidden", !visible);
tocButton.setAttribute("aria-expanded", visible);
tocButton.textContent = visible ? "×" : "";
tocButton.setAttribute("title", visible ? "Hide Table of Contents" : "Show Table of Contents");
html.classList.add('toc-hidden');
if (isPinned) {
html.classList.add('toc-pinned');
html.classList.add('toc-visible');
html.classList.remove('toc-hidden');
}
function updateTocPinned(pinned) {
html.classList.toggle("toc-pinned", pinned);
localStorage.setItem("tocPinned", pinned);
}
document.addEventListener("DOMContentLoaded", () => {
const tocButton = document.getElementById("toggle-toc");
const toc = document.getElementById("toc");
tocButton.addEventListener("click", () => {
isVisible = !isVisible;
isPinned = !isPinned;
updateTocVisibility(isVisible);
updateTocPinned(isPinned);
localStorage.setItem("tocVisible", isVisible);
localStorage.setItem("tocPinned", isPinned);
});
if (!tocButton || !toc) return;
tocButton.addEventListener("mouseenter", () => {
if (!isVisible) {
updateTocVisibility(true);
let isPinned = localStorage.getItem('tocPinned') === 'true';
function updateTocVisibility(visible) {
html.classList.toggle("toc-visible", visible);
html.classList.toggle("toc-hidden", !visible);
tocButton.setAttribute("aria-expanded", visible);
tocButton.textContent = visible ? "×" : "☰";
tocButton.setAttribute("title", visible ? "Hide Table of Contents" : "Show Table of Contents");
}
});
toc.addEventListener("mouseleave", () => {
if (!isVisible) {
updateTocVisibility(false);
}
});
tocButton.addEventListener("click", () => {
isPinned = !isPinned;
localStorage.setItem('tocPinned', isPinned);
html.classList.toggle('toc-pinned', isPinned);
updateTocVisibility(isPinned);
});
updateTocVisibility(isVisible);
});
tocButton.addEventListener("mouseenter", () => {
if (!isPinned) {
updateTocVisibility(true);
}
});
toc.addEventListener("mouseleave", () => {
if (!isPinned) {
updateTocVisibility(false);
}
});
updateTocVisibility(isPinned);
});
*/
})();
</script>
SCRIPT
output = output.sub(/<\/body>/, "#{script_tag}</body>")
output = output.sub('</body>', "#{script_tag}</body>")
output
end

163
boostlook_preview.rb Executable file
View File

@@ -0,0 +1,163 @@
#!/usr/bin/env ruby
require 'asciidoctor'
require 'listen'
require 'pathname'
require 'logger'
# AsciidocRenderer handles building AsciiDoc files, monitoring changes, and rendering the output in a browser.
class AsciidocRenderer
# Define our relevant constant paths
PATHS = {
jamfile: 'doc/Jamfile',
specimen_docinfo_footer: 'doc/specimen-docinfo-footer.html',
specimen_adoc: 'doc/specimen.adoc',
css: 'boostlook.css',
boostlook_rb: 'boostlook.rb',
output_dir: 'doc/html'
}.freeze
# OS-specific commands to open the default web browser
OS_BROWSER_COMMANDS = {
/darwin/ => 'open', # macOS
/linux/ => 'xdg-open', # Linux
/mingw|mswin/ => 'start' # Windows
}.freeze
def initialize
# Initialize the logger
@logger = Logger.new($stdout)
@logger.level = Logger::INFO
@logger.formatter = ->(_, _, _, msg) { "#{msg}\n" }
@file_opened = false # Flag to prevent multiple browser openings
@shutdown_requested = false # Flag to handle graceful shutdown
validate_b2 # Ensure Boost.Build is installed
end
# Entry point to run the renderer
def run
validate_files # Check for the presence of required files
initial_build # Perform the initial build and render
setup_signal_traps # Setup signal handlers for graceful shutdown
watch_files # Start watching for file changes
end
private
# Validates that all required files are present
def validate_files
required_files = [PATHS[:jamfile], PATHS[:specimen_docinfo_footer], PATHS[:specimen_adoc], PATHS[:css], PATHS[:boostlook_rb]]
missing_files = required_files.reject { |file| File.exist?(file) }
unless missing_files.empty?
missing_files.each { |file| @logger.error("Required file #{file} not found") }
exit 1
end
end
# Checks if the 'b2' command (Boost.Build) is available
def validate_b2
unless system('which b2 > /dev/null 2>&1')
@logger.error("'b2' command not found. Please install Boost.Build and ensure it's in your PATH.")
exit 1
end
end
# Builds the AsciiDoc project using Boost.Build
def build_asciidoc
Dir.chdir('doc') do
if system('b2')
@logger.info("Build successful")
true
else
@logger.error("Build failed")
false
end
end
end
# Opens the generated HTML file in the default web browser
def open_in_browser
return if @file_opened
cmd = OS_BROWSER_COMMANDS.find { |platform, _| RUBY_PLATFORM =~ platform }&.last
if cmd
system("#{cmd} #{PATHS[:output_dir]}/specimen.html")
@file_opened = true
else
@logger.warn("Unsupported OS. Please open #{PATHS[:output_dir]}/specimen.html manually")
end
end
# Performs the initial build and opens the result in the browser
def initial_build
if build_asciidoc && File.exist?("#{PATHS[:output_dir]}/specimen.html")
open_in_browser
@logger.info("Rendered #{PATHS[:specimen_adoc]} to #{PATHS[:output_dir]}/specimen.html")
else
@logger.error("Failed to generate #{PATHS[:output_dir]}/specimen.html")
end
end
# Sets up file listeners to watch for changes and trigger rebuilds
def watch_files
@listener = Listen.to('doc', '.') do |modified, added, removed|
handle_file_changes(modified, added, removed)
end
@listener.ignore(/doc\/html/) # Ignore changes in the output directory
@listener.start
@logger.info("Watching for changes in 'doc' and root directories (excluding 'doc/html')...")
# Keep the script running until a shutdown is requested
until @shutdown_requested
sleep 1
end
shutdown # Perform shutdown procedures
end
# Handles detected file changes by determining if a rebuild is necessary
def handle_file_changes(modified, added, removed)
@logger.debug("Modified files: #{modified.join(', ')}")
@logger.debug("Added files: #{added.join(', ')}") if added.any?
@logger.debug("Removed files: #{removed.join(', ')}") if removed.any?
relevant_files = [
File.expand_path(PATHS[:jamfile]),
File.expand_path(PATHS[:specimen_docinfo_footer]),
File.expand_path(PATHS[:specimen_adoc]),
File.expand_path(PATHS[:css]),
File.expand_path(PATHS[:boostlook_rb])
]
# Check if any of the changed files are relevant for rebuilding
changes_relevant = (modified + added + removed).any? do |file|
relevant_files.include?(File.expand_path(file))
end
if changes_relevant
@logger.info("Relevant changes detected, rebuilding...")
if build_asciidoc && File.exist?("#{PATHS[:output_dir]}/specimen.html")
open_in_browser
@logger.info("Re-rendered successfully")
end
end
end
# Sets up signal traps to handle graceful shutdown on interrupt or terminate signals
def setup_signal_traps
Signal.trap("INT") { @shutdown_requested = true }
Signal.trap("TERM") { @shutdown_requested = true }
end
# Performs shutdown procedures, such as stopping the file listener
def shutdown
@logger.info("Shutting down...")
@listener.stop if @listener
exit
end
end
# Instantiate and run the AsciidocRenderer
AsciidocRenderer.new.run

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
<style>
*:not(pre)>code { background: none; color: #600000; }
:not(pre):not([class^=L])>code { background: none; color: #600000; }
*:not(pre)>code { background: none; }
:not(pre):not([class^=L])>code { background: none; }
</style>

View File

@@ -438,7 +438,7 @@ See <<chars_format overview>> for description.
[#integral_usage_notes_]
* All built-in integral types are allowed except bool which is deleted
* from_chars for integral type is constexpr (BOOST_CHARCONV_CONSTEXPR is defined) when:
** compiled using `-std=c++14` or newer
** compiled using `-std=c++14` or newer
** using a compiler with `\__builtin_ is_constant_evaluated`
* These functions have been tested to support `\__int128` and `unsigned __int128`
@@ -993,4 +993,3 @@ This documentation is copyright 2022-2023 Peter Dimov and Matt Borland and is di
the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].
:leveloffset: -1

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).

5037
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>

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