<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2024-06-26" />
  <title>`async_scope` -- Creating scopes for non-sequential
concurrency</title>
  <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
      div.csl-block{margin-left: 1.5em;}
      ul.task-list{list-style: none;}
      pre > code.sourceCode { white-space: pre; position: relative; }
      pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
      pre > code.sourceCode > span:empty { height: 1.2em; }
      .sourceCode { overflow: visible; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      pre > code.sourceCode { white-space: pre-wrap; }
      pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::before
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -webkit-touch-callout: none; -webkit-user-select: none;
          -khtml-user-select: none; -moz-user-select: none;
          -ms-user-select: none; user-select: none;
          padding: 0 4px; width: 4em;
          color: #aaaaaa;
        }
      pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
      div.sourceCode
        {  background-color: #f6f8fa; }
      @media screen {
      pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span { } /* Normal */
      code span.al { color: #ff0000; } /* Alert */
      code span.an { } /* Annotation */
      code span.at { } /* Attribute */
      code span.bn { color: #9f6807; } /* BaseN */
      code span.bu { color: #9f6807; } /* BuiltIn */
      code span.cf { color: #00607c; } /* ControlFlow */
      code span.ch { color: #9f6807; } /* Char */
      code span.cn { } /* Constant */
      code span.co { color: #008000; font-style: italic; } /* Comment */
      code span.cv { color: #008000; font-style: italic; } /* CommentVar */
      code span.do { color: #008000; } /* Documentation */
      code span.dt { color: #00607c; } /* DataType */
      code span.dv { color: #9f6807; } /* DecVal */
      code span.er { color: #ff0000; font-weight: bold; } /* Error */
      code span.ex { } /* Extension */
      code span.fl { color: #9f6807; } /* Float */
      code span.fu { } /* Function */
      code span.im { } /* Import */
      code span.in { color: #008000; } /* Information */
      code span.kw { color: #00607c; } /* Keyword */
      code span.op { color: #af1915; } /* Operator */
      code span.ot { } /* Other */
      code span.pp { color: #6f4e37; } /* Preprocessor */
      code span.re { } /* RegionMarker */
      code span.sc { color: #9f6807; } /* SpecialChar */
      code span.ss { color: #9f6807; } /* SpecialString */
      code span.st { color: #9f6807; } /* String */
      code span.va { } /* Variable */
      code span.vs { color: #9f6807; } /* VerbatimString */
      code span.wa { color: #008000; font-weight: bold; } /* Warning */
      code.diff {color: #898887}
      code.diff span.va {color: #006e28}
      code.diff span.st {color: #bf0303}
  </style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
text-align: justify;
}
@media screen and (max-width: 30em) {
body {
margin: 1.5em;
}
}
div.wrapper {
max-width: 60em;
margin: auto;
}
ul {
list-style-type: none;
padding-left: 2em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
a {
text-decoration: none;
color: #4183C4;
}
a.hidden_link {
text-decoration: none;
color: inherit;
}
li {
margin-top: 0.6em;
margin-bottom: 0.6em;
}
h1, h2, h3, h4 {
position: relative;
line-height: 1;
}
a.self-link {
position: absolute;
top: 0;
left: calc(-1 * (3.5rem - 26px));
width: calc(3.5rem - 26px);
height: 2em;
text-align: center;
border: none;
transition: opacity .2s;
opacity: .5;
font-family: sans-serif;
font-weight: normal;
font-size: 83%;
}
a.self-link:hover { opacity: 1; }
a.self-link::before { content: "§"; }
ul > li:before {
content: "\2014";
position: absolute;
margin-left: -1.5em;
}
:target { background-color: #C9FBC9; }
:target .codeblock { background-color: #C9FBC9; }
:target ul { background-color: #C9FBC9; }
.abbr_ref { float: right; }
.folded_abbr_ref { float: right; }
:target .folded_abbr_ref { display: none; }
:target .unfolded_abbr_ref { float: right; display: inherit; }
.unfolded_abbr_ref { display: none; }
.secnum { display: inline-block; min-width: 35pt; }
.header-section-number { display: inline-block; min-width: 35pt; }
.annexnum { display: block; }
div.sourceLinkParent {
float: right;
}
a.sourceLink {
position: absolute;
opacity: 0;
margin-left: 10pt;
}
a.sourceLink:hover {
opacity: 1;
}
a.itemDeclLink {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
opacity: 0;
}
a.itemDeclLink:hover { opacity: 1; }
span.marginalizedparent {
position: relative;
left: -5em;
}
li span.marginalizedparent { left: -7em; }
li ul > li span.marginalizedparent { left: -9em; }
li ul > li ul > li span.marginalizedparent { left: -11em; }
li ul > li ul > li ul > li span.marginalizedparent { left: -13em; }
div.footnoteNumberParent {
position: relative;
left: -4.7em;
}
a.marginalized {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
}
a.enumerated_item_num {
position: relative;
left: -3.5em;
display: inline-block;
margin-right: -3em;
text-align: right;
width: 3em;
}
div.para { margin-bottom: 0.6em; margin-top: 0.6em; text-align: justify; }
div.section { text-align: justify; }
div.sentence { display: inline; }
span.indexparent {
display: inline;
position: relative;
float: right;
right: -1em;
}
a.index {
position: absolute;
display: none;
}
a.index:before { content: "⟵"; }

a.index:target {
display: inline;
}
.indexitems {
margin-left: 2em;
text-indent: -2em;
}
div.itemdescr {
margin-left: 3em;
}
.bnf {
font-family: serif;
margin-left: 40pt;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ncbnf {
font-family: serif;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
}
.ncsimplebnf {
font-family: serif;
font-style: italic;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
background: inherit; 
}
span.textnormal {
font-style: normal;
font-family: serif;
white-space: normal;
display: inline-block;
}
span.rlap {
display: inline-block;
width: 0px;
}
span.descr { font-style: normal; font-family: serif; }
span.grammarterm { font-style: italic; }
span.term { font-style: italic; }
span.terminal { font-family: monospace; font-style: normal; }
span.nonterminal { font-style: italic; }
span.tcode { font-family: monospace; font-style: normal; }
span.textbf { font-weight: bold; }
span.textsc { font-variant: small-caps; }
a.nontermdef { font-style: italic; font-family: serif; }
span.emph { font-style: italic; }
span.techterm { font-style: italic; }
span.mathit { font-style: italic; }
span.mathsf { font-family: sans-serif; }
span.mathrm { font-family: serif; font-style: normal; }
span.textrm { font-family: serif; }
span.textsl { font-style: italic; }
span.mathtt { font-family: monospace; font-style: normal; }
span.mbox { font-family: serif; font-style: normal; }
span.ungap { display: inline-block; width: 2pt; }
span.textit { font-style: italic; }
span.texttt { font-family: monospace; }
span.tcode_in_codeblock { font-family: monospace; font-style: normal; }
span.phantom { color: white; }

span.math { font-style: normal; }
span.mathblock {
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 1.2em;
margin-bottom: 1.2em;
text-align: center;
}
span.mathalpha {
font-style: italic;
}
span.synopsis {
font-weight: bold;
margin-top: 0.5em;
display: block;
}
span.definition {
font-weight: bold;
display: block;
}
.codeblock {
margin-left: 1.2em;
line-height: 127%;
}
.outputblock {
margin-left: 1.2em;
line-height: 127%;
}
div.itemdecl {
margin-top: 2ex;
}
code.itemdeclcode {
white-space: pre;
display: block;
}
span.textsuperscript {
vertical-align: super;
font-size: smaller;
line-height: 0;
}
.footnotenum { vertical-align: super; font-size: smaller; line-height: 0; }
.footnote {
font-size: small;
margin-left: 2em;
margin-right: 2em;
margin-top: 0.6em;
margin-bottom: 0.6em;
}
div.minipage {
display: inline-block;
margin-right: 3em;
}
div.numberedTable {
text-align: center;
margin: 2em;
}
div.figure {
text-align: center;
margin: 2em;
}
table {
border: 1px solid black;
border-collapse: collapse;
margin-left: auto;
margin-right: auto;
margin-top: 0.8em;
text-align: left;
hyphens: none; 
}
td, th {
padding-left: 1em;
padding-right: 1em;
vertical-align: top;
}
td.empty {
padding: 0px;
padding-left: 1px;
}
td.left {
text-align: left;
}
td.right {
text-align: right;
}
td.center {
text-align: center;
}
td.justify {
text-align: justify;
}
td.border {
border-left: 1px solid black;
}
tr.rowsep, td.cline {
border-top: 1px solid black;
}
tr.even, tr.odd {
border-bottom: 1px solid black;
}
tr.capsep {
border-top: 3px solid black;
border-top-style: double;
}
tr.header {
border-bottom: 3px solid black;
border-bottom-style: double;
}
th {
border-bottom: 1px solid black;
}
span.centry {
font-weight: bold;
}
div.table {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
width: 90%;
}
span.indented {
display: block;
margin-left: 2em;
margin-bottom: 1em;
margin-top: 1em;
}
ol.enumeratea { list-style-type: none; background: inherit; }
ol.enumerate { list-style-type: none; background: inherit; }

code.sourceCode > span { display: inline; }
</style>
  <link href="data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center"><code class="sourceCode default">async_scope</code>
– Creating scopes for non-sequential concurrency</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3149R5</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-06-26</td>
  </tr>
    <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
      <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      SG1 Parallelism and Concurrency<br>
      LEWG Library Evolution<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Ian Petersen<br>&lt;<a href="mailto:ispeters@meta.com" class="email">ispeters@meta.com</a>&gt;<br>
      Ján Ondrušek<br>&lt;<a href="mailto:ondrusek@meta.com" class="email">ondrusek@meta.com</a>&gt;<br>
      Jessica Wong<br>&lt;<a href="mailto:jesswong@meta.com" class="email">jesswong@meta.com</a>&gt;<br>
      Kirk Shoop<br>&lt;<a href="mailto:kirk.shoop@gmail.com" class="email">kirk.shoop@gmail.com</a>&gt;<br>
      Lee Howes<br>&lt;<a href="mailto:lwh@fb.com" class="email">lwh@fb.com</a>&gt;<br>
      Lucian Radu Teodorescu<br>&lt;<a href="mailto:lucteo@lucteo.ro" class="email">lucteo@lucteo.ro</a>&gt;<br>
    </td>
  </tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#changes" id="toc-changes"><span class="toc-section-number">1</span> Changes<span></span></a>
<ul>
<li><a href="#r5" id="toc-r5"><span class="toc-section-number">1.1</span> R5<span></span></a></li>
<li><a href="#r4" id="toc-r4"><span class="toc-section-number">1.2</span> R4<span></span></a></li>
<li><a href="#r3" id="toc-r3"><span class="toc-section-number">1.3</span> R3<span></span></a></li>
<li><a href="#r2" id="toc-r2"><span class="toc-section-number">1.4</span> R2<span></span></a></li>
<li><a href="#r1" id="toc-r1"><span class="toc-section-number">1.5</span> R1<span></span></a></li>
<li><a href="#r0" id="toc-r0"><span class="toc-section-number">1.6</span> R0<span></span></a></li>
</ul></li>
<li><a href="#introduction" id="toc-introduction"><span class="toc-section-number">2</span> Introduction<span></span></a>
<ul>
<li><a href="#implementation-experience" id="toc-implementation-experience"><span class="toc-section-number">2.1</span> Implementation
experience<span></span></a></li>
</ul></li>
<li><a href="#motivation" id="toc-motivation"><span class="toc-section-number">3</span> Motivation<span></span></a>
<ul>
<li><a href="#motivating-example" id="toc-motivating-example"><span class="toc-section-number">3.1</span> Motivating
example<span></span></a></li>
<li><a href="#counting_scope-and-let_with_async_scope-are-a-step-forward-towards-structured-concurrency" id="toc-counting_scope-and-let_with_async_scope-are-a-step-forward-towards-structured-concurrency"><span class="toc-section-number">3.2</span>
<code class="sourceCode default">counting_scope</code> and
<code class="sourceCode default">let_with_async_scope</code> are a step
forward towards Structured Concurrency<span></span></a></li>
</ul></li>
<li><a href="#examples-of-use" id="toc-examples-of-use"><span class="toc-section-number">4</span> Examples of use<span></span></a>
<ul>
<li><a href="#spawning-work-from-within-a-task" id="toc-spawning-work-from-within-a-task"><span class="toc-section-number">4.1</span> Spawning work from within a
task<span></span></a></li>
<li><a href="#starting-work-nested-within-a-framework" id="toc-starting-work-nested-within-a-framework"><span class="toc-section-number">4.2</span> Starting work nested within a
framework<span></span></a></li>
<li><a href="#starting-parallel-work" id="toc-starting-parallel-work"><span class="toc-section-number">4.3</span> Starting parallel
work<span></span></a></li>
<li><a href="#listener-loop-in-an-http-server" id="toc-listener-loop-in-an-http-server"><span class="toc-section-number">4.4</span> Listener loop in an HTTP
server<span></span></a></li>
<li><a href="#pluggable-functionality-through-composition" id="toc-pluggable-functionality-through-composition"><span class="toc-section-number">4.5</span> Pluggable functionality through
composition<span></span></a></li>
<li><a href="#recursively-spawning-work-until-completion" id="toc-recursively-spawning-work-until-completion"><span class="toc-section-number">4.6</span> Recursively spawning work until
completion<span></span></a>
<ul>
<li><a href="#let_with_async_scope-with-spawn" id="toc-let_with_async_scope-with-spawn"><span class="toc-section-number">4.6.1</span>
<code class="sourceCode default">let_with_async_scope</code> with
<code class="sourceCode default">spawn()</code><span></span></a></li>
<li><a href="#let_with_async_scope-with-spawn_future" id="toc-let_with_async_scope-with-spawn_future"><span class="toc-section-number">4.6.2</span>
<code class="sourceCode default">let_with_async_scope</code> with
<code class="sourceCode default">spawn_future()</code><span></span></a></li>
<li><a href="#counting_scope" id="toc-counting_scope"><span class="toc-section-number">4.6.3</span>
<code class="sourceCode default">counting_scope</code><span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#async-scope-usage-guide" id="toc-async-scope-usage-guide"><span class="toc-section-number">5</span> Async Scope, usage
guide<span></span></a>
<ul>
<li><a href="#definitions" id="toc-definitions"><span class="toc-section-number">5.1</span> Definitions<span></span></a></li>
<li><a href="#executionasync_scope_token" id="toc-executionasync_scope_token"><span class="toc-section-number">5.2</span>
<code class="sourceCode default">execution::async_scope_token</code><span></span></a></li>
<li><a href="#executionnest" id="toc-executionnest"><span class="toc-section-number">5.3</span>
<code class="sourceCode default">execution::nest</code><span></span></a></li>
<li><a href="#executionspawn" id="toc-executionspawn"><span class="toc-section-number">5.4</span>
<code class="sourceCode default">execution::spawn</code><span></span></a></li>
<li><a href="#executionspawn_future" id="toc-executionspawn_future"><span class="toc-section-number">5.5</span>
<code class="sourceCode default">execution::spawn_future</code><span></span></a></li>
<li><a href="#executionsimple_counting_scope" id="toc-executionsimple_counting_scope"><span class="toc-section-number">5.6</span>
<code class="sourceCode default">execution::simple_counting_scope</code><span></span></a>
<ul>
<li><a href="#simple_counting_scopesimple_counting_scope" id="toc-simple_counting_scopesimple_counting_scope"><span class="toc-section-number">5.6.1</span> <code class="sourceCode default">simple_counting_scope::simple_counting_scope</code><span></span></a></li>
<li><a href="#simple_counting_scopesimple_counting_scope-1" id="toc-simple_counting_scopesimple_counting_scope-1"><span class="toc-section-number">5.6.2</span> <code class="sourceCode default">simple_counting_scope::~simple_counting_scope</code><span></span></a></li>
<li><a href="#simple_counting_scopeget_token" id="toc-simple_counting_scopeget_token"><span class="toc-section-number">5.6.3</span>
<code class="sourceCode default">simple_counting_scope::get_token</code><span></span></a></li>
<li><a href="#simple_counting_scopeclose" id="toc-simple_counting_scopeclose"><span class="toc-section-number">5.6.4</span>
<code class="sourceCode default">simple_counting_scope::close</code><span></span></a></li>
<li><a href="#simple_counting_scopejoin" id="toc-simple_counting_scopejoin"><span class="toc-section-number">5.6.5</span>
<code class="sourceCode default">simple_counting_scope::join</code><span></span></a></li>
<li><a href="#simple_counting_scopetokennest" id="toc-simple_counting_scopetokennest"><span class="toc-section-number">5.6.6</span> <code class="sourceCode default">simple_counting_scope::token::nest</code><span></span></a></li>
</ul></li>
<li><a href="#executioncounting_scope" id="toc-executioncounting_scope"><span class="toc-section-number">5.7</span>
<code class="sourceCode default">execution::counting_scope</code><span></span></a>
<ul>
<li><a href="#counting_scopecounting_scope" id="toc-counting_scopecounting_scope"><span class="toc-section-number">5.7.1</span>
<code class="sourceCode default">counting_scope::counting_scope</code><span></span></a></li>
<li><a href="#counting_scopecounting_scope-1" id="toc-counting_scopecounting_scope-1"><span class="toc-section-number">5.7.2</span>
<code class="sourceCode default">counting_scope::~counting_scope</code><span></span></a></li>
<li><a href="#counting_scopeget_token" id="toc-counting_scopeget_token"><span class="toc-section-number">5.7.3</span>
<code class="sourceCode default">counting_scope::get_token</code><span></span></a></li>
<li><a href="#counting_scopeclose" id="toc-counting_scopeclose"><span class="toc-section-number">5.7.4</span>
<code class="sourceCode default">counting_scope::close</code><span></span></a></li>
<li><a href="#counting_scoperequest_stop" id="toc-counting_scoperequest_stop"><span class="toc-section-number">5.7.5</span>
<code class="sourceCode default">counting_scope::request_stop</code><span></span></a></li>
<li><a href="#counting_scopejoin" id="toc-counting_scopejoin"><span class="toc-section-number">5.7.6</span>
<code class="sourceCode default">counting_scope::join</code><span></span></a></li>
<li><a href="#counting_scopetokennest" id="toc-counting_scopetokennest"><span class="toc-section-number">5.7.7</span>
<code class="sourceCode default">counting_scope::token::nest</code><span></span></a></li>
</ul></li>
<li><a href="#when-to-use-counting_scope-vs-p3296r0s-let_with_async_scope" id="toc-when-to-use-counting_scope-vs-p3296r0s-let_with_async_scope"><span class="toc-section-number">5.8</span> When to use
<code class="sourceCode default">counting_scope</code> vs <span class="citation" data-cites="P3296R0">[<span>P3296R0</span>]</span>’s
<code class="sourceCode default">let_with_async_scope</code><span></span></a></li>
</ul></li>
<li><a href="#design-considerations" id="toc-design-considerations"><span class="toc-section-number">6</span>
Design considerations<span></span></a>
<ul>
<li><a href="#shape-of-the-given-sender" id="toc-shape-of-the-given-sender"><span class="toc-section-number">6.1</span> Shape of the given
sender<span></span></a>
<ul>
<li><a href="#constraints-on-set_value" id="toc-constraints-on-set_value"><span class="toc-section-number">6.1.1</span> Constraints on
<code class="sourceCode default">set_value()</code><span></span></a></li>
<li><a href="#handling-errors-in-spawn" id="toc-handling-errors-in-spawn"><span class="toc-section-number">6.1.2</span> Handling errors in
<code class="sourceCode default">spawn()</code><span></span></a></li>
<li><a href="#handling-stop-signals-in-spawn" id="toc-handling-stop-signals-in-spawn"><span class="toc-section-number">6.1.3</span> Handling stop signals in
<code class="sourceCode default">spawn()</code><span></span></a></li>
<li><a href="#no-shape-restrictions-for-the-senders-passed-to-spawn_future-and-nest" id="toc-no-shape-restrictions-for-the-senders-passed-to-spawn_future-and-nest"><span class="toc-section-number">6.1.4</span> No shape restrictions for the
senders passed to <code class="sourceCode default">spawn_future()</code>
and <code class="sourceCode default">nest()</code><span></span></a></li>
</ul></li>
<li><a href="#p2300s-start_detached" id="toc-p2300s-start_detached"><span class="toc-section-number">6.2</span> P2300’s
<code class="sourceCode default">start_detached()</code><span></span></a></li>
<li><a href="#p2300s-ensure_started" id="toc-p2300s-ensure_started"><span class="toc-section-number">6.3</span> P2300’s
<code class="sourceCode default">ensure_started()</code><span></span></a></li>
<li><a href="#supporting-the-pipe-operator" id="toc-supporting-the-pipe-operator"><span class="toc-section-number">6.4</span> Supporting the pipe
operator<span></span></a></li>
<li><a href="#problems-protecting-allocators-with-counting_scope" id="toc-problems-protecting-allocators-with-counting_scope"><span class="toc-section-number">6.5</span> Problems Protecting Allocators
with
<code class="sourceCode default">counting_scope</code><span></span></a>
<ul>
<li><a href="#the-problem" id="toc-the-problem"><span class="toc-section-number">6.5.1</span> The
Problem<span></span></a></li>
<li><a href="#some-solutions" id="toc-some-solutions"><span class="toc-section-number">6.5.2</span> Some
Solutions<span></span></a></li>
<li><a href="#discussion-of-reasons-to-reject-options-1-5" id="toc-discussion-of-reasons-to-reject-options-1-5"><span class="toc-section-number">6.5.3</span> Discussion of Reasons to Reject
Options 1-5<span></span></a></li>
<li><a href="#discussion-of-option-6" id="toc-discussion-of-option-6"><span class="toc-section-number">6.5.4</span> Discussion of Option
6<span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#naming" id="toc-naming"><span class="toc-section-number">7</span> Naming<span></span></a>
<ul>
<li><a href="#nest" id="toc-nest"><span class="toc-section-number">7.1</span>
<code class="sourceCode default">nest()</code><span></span></a></li>
<li><a href="#async_scope_token" id="toc-async_scope_token"><span class="toc-section-number">7.2</span>
<code class="sourceCode default">async_scope_token</code><span></span></a></li>
<li><a href="#spawn" id="toc-spawn"><span class="toc-section-number">7.3</span>
<code class="sourceCode default">spawn()</code><span></span></a></li>
<li><a href="#spawn_future" id="toc-spawn_future"><span class="toc-section-number">7.4</span>
<code class="sourceCode default">spawn_future()</code><span></span></a></li>
<li><a href="#simple_counting_scope" id="toc-simple_counting_scope"><span class="toc-section-number">7.5</span>
<code class="sourceCode default">simple_counting_scope</code><span></span></a></li>
<li><a href="#counting_scope-1" id="toc-counting_scope-1"><span class="toc-section-number">7.6</span>
<code class="sourceCode default">counting_scope</code><span></span></a>
<ul>
<li><a href="#counting_scopejoin-1" id="toc-counting_scopejoin-1"><span class="toc-section-number">7.6.1</span>
<code class="sourceCode default">counting_scope::join()</code><span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#specification" id="toc-specification"><span class="toc-section-number">8</span> Specification<span></span></a>
<ul>
<li><a href="#executionasync_scope_token-1" id="toc-executionasync_scope_token-1"><span class="toc-section-number">8.1</span>
<code class="sourceCode default">execution::async_scope_token</code><span></span></a></li>
<li><a href="#executionnest-1" id="toc-executionnest-1"><span class="toc-section-number">8.2</span>
<code class="sourceCode default">execution::nest</code><span></span></a></li>
<li><a href="#executionspawn-1" id="toc-executionspawn-1"><span class="toc-section-number">8.3</span>
<code class="sourceCode default">execution::spawn</code><span></span></a></li>
<li><a href="#executionspawn_future-1" id="toc-executionspawn_future-1"><span class="toc-section-number">8.4</span>
<code class="sourceCode default">execution::spawn_future</code><span></span></a></li>
<li><a href="#executionsimple_counting_scope-1" id="toc-executionsimple_counting_scope-1"><span class="toc-section-number">8.5</span>
<code class="sourceCode default">execution::simple_counting_scope</code><span></span></a></li>
<li><a href="#executioncounting_scope-1" id="toc-executioncounting_scope-1"><span class="toc-section-number">8.6</span>
<code class="sourceCode default">execution::counting_scope</code><span></span></a></li>
</ul></li>
<li><a href="#acknowledgements" id="toc-acknowledgements"><span class="toc-section-number">9</span>
Acknowledgements<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">10</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" id="changes"><span class="header-section-number">1</span> Changes<a href="#changes" class="self-link"></a></h1>
<h2 data-number="1.1" id="r5"><span class="header-section-number">1.1</span> R5<a href="#r5" class="self-link"></a></h2>
<ul>
<li>Clarify that the
<em><code class="sourceCode default">nest-sender</code></em>’s operation
state must destroy its child operation state before decrementing the
scope’s reference count.</li>
<li>Add naming discussion.</li>
<li>Discuss a memory allocator lifetime concern raised by Lewis Baker
and several options for resolving it.</li>
</ul>
<h2 data-number="1.2" id="r4"><span class="header-section-number">1.2</span> R4<a href="#r4" class="self-link"></a></h2>
<ul>
<li>Permit caller of
<code class="sourceCode default">spawn_future()</code> to provide a stop
token in the optional environment argument.</li>
<li>Remove <code class="sourceCode default">[[nodiscard]]</code>.</li>
<li>Make <code class="sourceCode default">simple_counting_scope::token::token()</code>
and
<code class="sourceCode default">counting_scope::token::token()</code>
explicit and exposition-only.</li>
<li>Remove redundant
<code class="sourceCode default">concept async_scope</code>.</li>
<li>Remove last vestiges of
<code class="sourceCode default">let_with_async_scope</code>.</li>
<li>Add some wording to a new <a href="#specification">Specification</a>
section</li>
</ul>
<h2 data-number="1.3" id="r3"><span class="header-section-number">1.3</span> R3<a href="#r3" class="self-link"></a></h2>
<ul>
<li>Update slide code to be exception safe</li>
<li>Split the async scope concept into a scope and token; update
<code class="sourceCode default">counting_scope</code> to match</li>
<li>Rename <code class="sourceCode default">counting_scope</code> to
<code class="sourceCode default">simple_counting_scope</code> and give
the name <code class="sourceCode default">counting_scope</code> to a
scope with a stop source</li>
<li>Add example for recursively spawned work using
<code class="sourceCode default">let_with_async_scope</code> and
<code class="sourceCode default">counting_scope</code></li>
</ul>
<h2 data-number="1.4" id="r2"><span class="header-section-number">1.4</span> R2<a href="#r2" class="self-link"></a></h2>
<ul>
<li><p>Update
<code class="sourceCode default">counting_scope::nest()</code> to
explain when the scope’s count of outstanding senders is decremented and
remove <code class="sourceCode default">counting_scope::joined()</code>,
<code class="sourceCode default">counting_scope::join_started()</code>,
and <code class="sourceCode default">counting_scope::use_count()</code>
on advice of SG1 straw poll:</p>
<blockquote>
<p>forward P3149R1 to LEWG for inclusion in C++26 after P2300 is
included in C++26, with notes:</p>
<ol type="1">
<li>the point of refcount decrement to be moved after the child
operation state is destroyed</li>
<li>a future paper should explore the design for cancellation of
scopes</li>
<li>observers (joined, join_started, use_count) can be removed</li>
</ol>
<table style="width:28%;">
<colgroup>
<col style="width: 5%" />
<col style="width: 5%" />
<col style="width: 5%" />
<col style="width: 5%" />
<col style="width: 5%" />
</colgroup>
<thead>
<tr class="header">
<th style="text-align: right;"><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th style="text-align: right;"><div style="text-align:center">
<strong>F</strong>
</div></th>
<th style="text-align: right;"><div style="text-align:center">
<strong>N</strong>
</div></th>
<th style="text-align: right;"><div style="text-align:center">
<strong>A</strong>
</div></th>
<th style="text-align: right;"><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: right;">10</td>
<td style="text-align: right;">14</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">1</td>
</tr>
</tbody>
</table>
<p>Consensus</p>
<p>SA: we are moving something without wide implementation experience,
the version with experience has cancellation of scopes</p>
</blockquote></li>
<li><p>Add a fourth state to
<code class="sourceCode default">counting_scope</code> so that it can be
used as a data-member safely</p></li>
</ul>
<h2 data-number="1.5" id="r1"><span class="header-section-number">1.5</span> R1<a href="#r1" class="self-link"></a></h2>
<ul>
<li>Add implementation experience</li>
<li>Incorporate pre-meeting feedback from Eric Niebler</li>
</ul>
<h2 data-number="1.6" id="r0"><span class="header-section-number">1.6</span> R0<a href="#r0" class="self-link"></a></h2>
<ul>
<li>First revision</li>
</ul>
<h1 data-number="2" id="introduction"><span class="header-section-number">2</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p><span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span> lays the groundwork for writing
structured concurrent programs in C++ but it leaves three important
scenarios under- or unaddressed:</p>
<ol type="1">
<li>progressively structuring an existing, unstructured concurrent
program;</li>
<li>starting a dynamic number of parallel tasks without “losing track”
of them; and</li>
<li>opting in to eager execution of sender-shaped work when
appropriate.</li>
</ol>
<p>This paper describes the utilities needed to address the above
scenarios within the following constraints:</p>
<ul>
<li><em>No detached work by default;</em> as specified in <span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span>, the
<code class="sourceCode default">start_detached</code> and
<code class="sourceCode default">ensure_started</code> algorithms invite
users to start concurrent work with no built-in way to know when that
work has finished.
<ul>
<li>Such so-called “detached work” is undesirable; without a way to know
when detached work is done, it is difficult know when it is safe to
destroy any resources referred to by the work. Ad hoc solutions to this
shutdown problem add unnecessary complexity that can be avoided by
ensuring all concurrent work is “attached”.</li>
<li><span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span>’s introduction of structured
concurrency to C++ will make async programming with C++ much easier but
experienced C++ programmers typically believe that async C++ is “just
hard” and that starting async work <em>means</em> starting detached work
(even if they are not thinking about the distinction between attached
and detached work) so adapting to a post-<span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span> world will require unlearning
many deprecated patterns. It is thus useful as a teaching aid to remove
the unnecessary temptation of falling back on old habits.</li>
</ul></li>
<li><em>No dependencies besides <span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span>;</em> it will be important for
the success of <span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span> that
existing code bases can migrate from unstructured concurrency to
structured concurrency in an incremental way so tools for progressively
structuring code should not take on risk in the form of unnecessary
dependencies.</li>
</ul>
<p>The proposed solution comes in the following parts:</p>
<ul>
<li><code class="sourceCode cpp"><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Token, <span class="kw">class</span> Sender<span class="op">&gt;</span> <span class="kw">concept</span> async_scope_token</code>;</li>
<li><code class="sourceCode cpp">sender <span class="kw">auto</span> nest<span class="op">(</span>sender <span class="kw">auto</span><span class="op">&amp;&amp;</span> snd, async_scope_token <span class="kw">auto</span> token<span class="op">)</span></code>;</li>
<li><code class="sourceCode cpp"><span class="dt">void</span> spawn<span class="op">(</span>sender <span class="kw">auto</span><span class="op">&amp;&amp;</span> snd, async_scope_token <span class="kw">auto</span> token, <span class="kw">auto</span><span class="op">&amp;&amp;</span> env<span class="op">)</span></code>;</li>
<li><code class="sourceCode cpp">sender <span class="kw">auto</span> spawn_future<span class="op">(</span>sender <span class="kw">auto</span><span class="op">&amp;&amp;</span> snd, async_scope_token <span class="kw">auto</span> token, <span class="kw">auto</span><span class="op">&amp;&amp;</span> env<span class="op">)</span></code>;</li>
<li>Proposed in <span class="citation" data-cites="P3296R0">[<a href="#ref-P3296R0" role="doc-biblioref">P3296R0</a>]</span>: <code class="sourceCode cpp">sender <span class="kw">auto</span> let_with_async_scope<span class="op">(</span>callable <span class="kw">auto</span><span class="op">&amp;&amp;</span> senderFactory<span class="op">)</span></code>;</li>
<li><code class="sourceCode cpp"><span class="kw">struct</span> simple_counting_scope</code>;
and</li>
<li><code class="sourceCode cpp"><span class="kw">struct</span> counting_scope</code>.</li>
</ul>
<h2 data-number="2.1" id="implementation-experience"><span class="header-section-number">2.1</span> Implementation experience<a href="#implementation-experience" class="self-link"></a></h2>
<p>The general concept of an async scope to manage work has been
deployed broadly at Meta. Code written with Folly’s coroutine library,
<span class="citation" data-cites="follycoro">[<a href="#ref-follycoro" role="doc-biblioref"><code class="sourceCode default">folly::coro</code></a>]</span>,
uses <span class="citation" data-cites="follyasyncscope">[<a href="#ref-follyasyncscope" role="doc-biblioref"><code class="sourceCode default">folly::coro::AsyncScope</code></a>]</span>
to safely launch awaitables. Most code written with Unifex, an
implementation of an earlier version of the <em>Sender/Receiver</em>
model proposed in <span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span>, uses <span class="citation" data-cites="asyncscopeunifexv1">[<a href="#ref-asyncscopeunifexv1" role="doc-biblioref"><code class="sourceCode default">unifex::v1::async_scope</code></a>]</span>,
although experience with the v1 design led to the creation of <span class="citation" data-cites="asyncscopeunifexv2">[<a href="#ref-asyncscopeunifexv2" role="doc-biblioref"><code class="sourceCode default">unifex::v2::async_scope</code></a>]</span>,
which has a smaller interface and a cleaner definition of
responsibility.</p>
<p>As an early adopter of Unifex, <span class="citation" data-cites="rsys">[<a href="#ref-rsys" role="doc-biblioref">rsys</a>]</span> (Meta’s cross-platform voip client
library) became the entry point for structured concurrency in mobile
code at Meta. We originally built rsys with an unstructured asynchrony
model built around posting callbacks to threads in order to optimize for
binary size. However, this came at the expense of developer velocity due
to the increasing cost of debugging deadlocks and crashes resulting from
race conditions.</p>
<p>We decided to adopt Unifex and refactor towards a more structured
architecture to address these problems systematically. Converting an
unstructured production codebase to a structured one is such a large
project that it needs to be done in phases. As we began to convert
callbacks to senders/tasks, we quickly realized that we needed a safe
place to start structured asynchronous work in an unstructured
environment. We addressed this need with
<code class="sourceCode default">unifex::v1::async_scope</code> paired
with an executor to address a recurring pattern:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Before</strong>
</div></th>
<th><div style="text-align:center">
<strong>After</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div>

<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Abstraction for thread that has the ability</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="co">// to execute units of work.</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Executor <span class="op">{</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span><span class="op">:</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">virtual</span> <span class="dt">void</span> add<span class="op">(</span>Func function<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="co">// Example class</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Foo <span class="op">{</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>shared_ptr<span class="op">&lt;</span>Executor<span class="op">&gt;</span> exec_;</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span><span class="op">:</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> doSomething<span class="op">()</span> <span class="op">{</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>     <span class="kw">auto</span> asyncWork <span class="op">=</span> <span class="op">[&amp;]()</span> <span class="op">{</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>       <span class="co">// do something</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>     <span class="op">}</span>;</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>     exec_<span class="op">-&gt;</span>add<span class="op">(</span>asyncWork<span class="op">)</span>;</span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>

</div></td>
<td><div>

<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Utility class for executing async work on an</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="co">// async_scope and on the provided executor</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> ExecutorAsyncScopePair <span class="op">{</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  unifex<span class="op">::</span>v1<span class="op">::</span>async_scope scope_;</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  ExecutorScheduler exec_</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span><span class="op">:</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> add<span class="op">(</span>Func func<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>    scope_<span class="op">.</span>detached_spawn_call_on<span class="op">(</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>      exec_, func<span class="op">)</span>;</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> cleanup<span class="op">()</span> <span class="op">{</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> scope_<span class="op">.</span>cleanup<span class="op">()</span>;</span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a><span class="co">// Example class</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Foo <span class="op">{</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a> std<span class="op">::</span>shared_ptr<span class="op">&lt;</span>ExecutorAsyncScopePair<span class="op">&gt;</span> exec_;</span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span><span class="op">:</span></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a>  <span class="op">~</span>Foo<span class="op">()</span> <span class="op">{</span></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a>    sync_wait<span class="op">(</span>exec_<span class="op">-&gt;</span>cleanup<span class="op">())</span>;</span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> doSomething<span class="op">()</span> <span class="op">{</span></span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> asyncWork <span class="op">=</span> <span class="op">[&amp;]()</span> <span class="op">{</span></span>
<span id="cb2-29"><a href="#cb2-29" aria-hidden="true" tabindex="-1"></a>      <span class="co">// do something</span></span>
<span id="cb2-30"><a href="#cb2-30" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb2-31"><a href="#cb2-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-32"><a href="#cb2-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-33"><a href="#cb2-33" aria-hidden="true" tabindex="-1"></a>   exec_<span class="op">-&gt;</span>add<span class="op">(</span>asyncWork<span class="op">)</span>;</span>
<span id="cb2-34"><a href="#cb2-34" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb2-35"><a href="#cb2-35" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>

</div></td>
</tr>
</tbody>
</table>
<p>This broadly worked but we discovered that the above design coupled
with the v1 API allowed for too many redundancies and conflated too many
responsibilities (scoping async work, associating work with a stop
source, and transferring scoped work to a new scheduler).</p>
<p>We learned that making each component own a distinct responsibility
will minimize the confusion and increase the structured concurrency
adoption rate. The above example was an intuitive use of async_scope
because the concept of a “scoped executor” was familiar to many
engineers and is a popular async pattern in other programming languages.
However, the above design abstracted away some of the APIs in
async_scope that explicitly asked for a scheduler, which would have
helped challenge the assumption engineers made about async_scope being
an instance of a “scoped executor”.</p>
<p>Cancellation was an unfamiliar topic for engineers within the context
of asynchronous programming. The
<code class="sourceCode default">v1::async_scope</code> provided both
<code class="sourceCode default">cleanup()</code> and
<code class="sourceCode default">complete()</code> to give engineers the
freedom to decide between canceling work or waiting for work to finish.
The different nuances on when this should happen and how it happens
ended up being an obstacle that engineers didn’t want to deal with.</p>
<p>Over time, we also found redundancies in the way
<code class="sourceCode default">v1::async_scope</code> and other
algorithms were implemented and identified other use cases that could
benefit from a different kind of async scope. This motivated us to
create <code class="sourceCode default">v2::async_scope</code> which
only has one responsibility (scope), and
<code class="sourceCode default">nest</code> which helped us improve
maintainability and flexibility of Unifex.</p>
<p>The unstructured nature of
<code class="sourceCode default">cleanup()</code>/<code class="sourceCode default">complete()</code>
in a partially structured codebase introduced deadlocks when engineers
nested the
<code class="sourceCode default">cleanup()</code>/<code class="sourceCode default">complete()</code>
sender in the scope being joined. This risk of deadlock remains with
<code class="sourceCode default">v2::async_scope::join()</code> however,
we do think this risk can be managed and is worth the tradeoff in
exchange for a more coherent architecture that has fewer crashes. For
example, we have experienced a significant reduction in these types of
deadlocks once engineers understood that
<code class="sourceCode default">join()</code> is a destructor-like
operation that needs to be run only by the scope’s owner. Since there is
no language support to manage async lifetimes automatically, this
insight was key in preventing these types of deadlocks. Although this
breakthrough was a result of strong guidance from experts, we believe
that the simpler design of
<code class="sourceCode default">v2::async_scope</code> would make this
a little easier.</p>
<p>We strongly believe that async_scope was necessary for making
structured concurrency possible within rsys, and we believe that the
improvements we made with
<code class="sourceCode default">v2::async_scope</code> will make the
adoption of P2300 more accessible.</p>
<h1 data-number="3" id="motivation"><span class="header-section-number">3</span> Motivation<a href="#motivation" class="self-link"></a></h1>
<h2 data-number="3.1" id="motivating-example"><span class="header-section-number">3.1</span> Motivating example<a href="#motivating-example" class="self-link"></a></h2>
<p>Let us assume the following code:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> ex <span class="op">=</span> std<span class="op">::</span>execution;</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> work_context;</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> work_item;</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> do_work<span class="op">(</span>work_context<span class="op">&amp;</span>, work_item<span class="op">*)</span>;</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span>work_item<span class="op">*&gt;</span> get_work_items<span class="op">()</span>;</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>    static_thread_pool my_pool<span class="op">{</span><span class="dv">8</span><span class="op">}</span>;</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>    work_context ctx; <span class="co">// create a global context for the application</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span>work_item<span class="op">*&gt;</span> items <span class="op">=</span> get_work_items<span class="op">()</span>;</span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> item <span class="op">:</span> items<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>        <span class="co">// Spawn some work dynamically</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>        ex<span class="op">::</span>sender <span class="kw">auto</span> snd <span class="op">=</span> ex<span class="op">::</span>transfer_just<span class="op">(</span>my_pool<span class="op">.</span>get_scheduler<span class="op">()</span>, item<span class="op">)</span> <span class="op">|</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>                              ex<span class="op">::</span>then<span class="op">([&amp;](</span>work_item<span class="op">*</span> item<span class="op">)</span> <span class="op">{</span> do_work<span class="op">(</span>ctx, item<span class="op">)</span>; <span class="op">})</span>;</span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a>        ex<span class="op">::</span>start_detached<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>snd<span class="op">))</span>;</span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a>    <span class="co">// `ctx` and `my_pool` are destroyed</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>In this example we are creating parallel work based on the given
input vector. All the work will be spawned on the local
<code class="sourceCode default">static_thread_pool</code> object, and
will use a shared <code class="sourceCode default">work_context</code>
object.</p>
<p>Because the number of work items is dynamic, one is forced to use
<code class="sourceCode default">start_detached()</code> from <span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span> (or something equivalent) to
dynamically spawn work. <span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span> doesn’t
provide any facilities to spawn dynamic work and return a sender (i.e.,
something like <code class="sourceCode default">when_all</code> but with
a dynamic number of input senders).</p>
<p>Using <code class="sourceCode default">start_detached()</code> here
follows the <em>fire-and-forget</em> style, meaning that we have no
control over, or awareness of, the completion of the async work that is
being spawned.</p>
<p>At the end of the function, we are destroying the
<code class="sourceCode default">work_context</code> and the
<code class="sourceCode default">static_thread_pool</code>. But at that
point, we don’t know whether all the spawned async work has completed.
If any of the async work is incomplete, this might lead to crashes.</p>
<p><span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span> doesn’t give us out-of-the-box
facilities to use in solving these types of problems.</p>
<p>This paper proposes the
<code class="sourceCode default">counting_scope</code> and <span class="citation" data-cites="P3296R0">[<a href="#ref-P3296R0" role="doc-biblioref">P3296R0</a>]</span>’s
<code class="sourceCode default">let_with_async_scope</code> facilities
that would help us avoid the invalid behavior. With
<code class="sourceCode default">counting_scope</code>, one might write
safe code this way:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> ex <span class="op">=</span> std<span class="op">::</span>execution;</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> work_context;</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> work_item;</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> do_work<span class="op">(</span>work_context<span class="op">&amp;</span>, work_item<span class="op">*)</span>;</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span>work_item<span class="op">*&gt;</span> get_work_items<span class="op">()</span>;</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>    static_thread_pool my_pool<span class="op">{</span><span class="dv">8</span><span class="op">}</span>;</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>    work_context ctx;         <span class="co">// create a global context for the application</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>counting_scope scope; <span class="co">// create this *after* the resources it protects</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>    <span class="co">// make sure we always join</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>    unifex<span class="op">::</span>scope_guard join <span class="op">=</span> <span class="op">[&amp;]()</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>      <span class="co">// wait for all nested work to finish</span></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a>      this_thread<span class="op">::</span>sync_wait<span class="op">(</span>scope<span class="op">.</span>join<span class="op">())</span>; <span class="co">// NEW!</span></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span>work_item<span class="op">*&gt;</span> items <span class="op">=</span> get_work_items<span class="op">()</span>;</span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> item <span class="op">:</span> items<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a>      <span class="co">// Spawn some work dynamically</span></span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a>      ex<span class="op">::</span>sender <span class="kw">auto</span> snd <span class="op">=</span> ex<span class="op">::</span>transfer_just<span class="op">(</span>my_pool<span class="op">.</span>get_scheduler<span class="op">()</span>, item<span class="op">)</span> <span class="op">|</span></span>
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a>                            ex<span class="op">::</span>then<span class="op">([&amp;](</span>work_item<span class="op">*</span> item<span class="op">)</span> <span class="op">{</span> do_work<span class="op">(</span>ctx, item<span class="op">)</span>; <span class="op">})</span>;</span>
<span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-25"><a href="#cb4-25" aria-hidden="true" tabindex="-1"></a>      <span class="co">// start `snd` as before, but associate the spawned work with `scope` so that it can</span></span>
<span id="cb4-26"><a href="#cb4-26" aria-hidden="true" tabindex="-1"></a>      <span class="co">// be awaited before destroying the resources referenced by the work (i.e. `my_pool`</span></span>
<span id="cb4-27"><a href="#cb4-27" aria-hidden="true" tabindex="-1"></a>      <span class="co">// and `ctx`)</span></span>
<span id="cb4-28"><a href="#cb4-28" aria-hidden="true" tabindex="-1"></a>      ex<span class="op">::</span>spawn<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>snd<span class="op">)</span>, scope<span class="op">.</span>get_token<span class="op">())</span>; <span class="co">// NEW!</span></span>
<span id="cb4-29"><a href="#cb4-29" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb4-30"><a href="#cb4-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-31"><a href="#cb4-31" aria-hidden="true" tabindex="-1"></a>    <span class="co">// `ctx` and `my_pool` are destroyed *after* they are no longer referenced</span></span>
<span id="cb4-32"><a href="#cb4-32" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>With <span class="citation" data-cites="P3296R0">[<a href="#ref-P3296R0" role="doc-biblioref">P3296R0</a>]</span>’s
<code class="sourceCode default">let_with_async_scope</code>, one might
write safe code this way:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> ex <span class="op">=</span> std<span class="op">::</span>execution;</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> work_context;</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> work_item;</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> do_work<span class="op">(</span>work_context<span class="op">&amp;</span>, work_item<span class="op">*)</span>;</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span>work_item<span class="op">*&gt;</span> get_work_items<span class="op">()</span>;</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>  static_thread_pool my_pool<span class="op">{</span><span class="dv">8</span><span class="op">}</span>;</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>  work_context ctx;         <span class="co">// create a global context for the application</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>  this_thread<span class="op">::</span>sync_wait<span class="op">(</span>ex<span class="op">::</span>let_with_async_scope<span class="op">(</span>ex<span class="op">::</span>just<span class="op">(</span>get_work_items<span class="op">())</span>, <span class="op">[&amp;](</span><span class="kw">auto</span> scope<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> item <span class="op">:</span> items<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a>      <span class="co">// Spawn some work dynamically</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a>      ex<span class="op">::</span>sender <span class="kw">auto</span> snd <span class="op">=</span> ex<span class="op">::</span>transfer_just<span class="op">(</span>my_pool<span class="op">.</span>get_scheduler<span class="op">()</span>, item<span class="op">)</span> <span class="op">|</span></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a>                            ex<span class="op">::</span>then<span class="op">([&amp;](</span>work_item<span class="op">*</span> item<span class="op">)</span> <span class="op">{</span> do_work<span class="op">(</span>ctx, item<span class="op">)</span>; <span class="op">})</span>;</span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>      <span class="co">// start `snd` as before, but associate the spawned work with `scope` so that it can</span></span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a>      <span class="co">// be awaited before destroying the resources referenced by the work (i.e. `my_pool`</span></span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a>      <span class="co">// and `ctx`)</span></span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a>      ex<span class="op">::</span>spawn<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>snd<span class="op">)</span>, scope<span class="op">)</span>; <span class="co">// NEW!</span></span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb5-23"><a href="#cb5-23" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> just<span class="op">()</span>;</span>
<span id="cb5-24"><a href="#cb5-24" aria-hidden="true" tabindex="-1"></a>  <span class="op">}))</span>;</span>
<span id="cb5-25"><a href="#cb5-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-26"><a href="#cb5-26" aria-hidden="true" tabindex="-1"></a>  <span class="co">// `ctx` and `my_pool` are destroyed *after* they are no longer referenced</span></span>
<span id="cb5-27"><a href="#cb5-27" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Simplifying the above into something that fits in a Tony Table to
highlight the differences gives us:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Before</strong>
</div></th>
<th><div style="text-align:center">
<strong>With
<code class="sourceCode default">counting_scope</code></strong>
</div></th>
<th><div style="text-align:center">
<strong>With
<code class="sourceCode default">let_with_async_scope</code></strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div>

<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> ex <span class="op">=</span> std<span class="op">::</span>execution;</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> context;</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>ex<span class="op">::</span>sender <span class="kw">auto</span> work<span class="op">(</span><span class="kw">const</span> context<span class="op">&amp;)</span>;</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>  context ctx;</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>  ex<span class="op">::</span>sender <span class="kw">auto</span> snd <span class="op">=</span> work<span class="op">(</span>ctx<span class="op">)</span>;</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>  <span class="co">// fire and forget</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>  ex<span class="op">::</span>start_detached<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>snd<span class="op">))</span>;</span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a>  <span class="co">// `ctx` is destroyed, perhaps before</span></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a>  <span class="co">// `snd` is done</span></span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

</div></td>
<td><div>

<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> ex <span class="op">=</span> std<span class="op">::</span>execution;</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> context;</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>ex<span class="op">::</span>sender <span class="kw">auto</span> work<span class="op">(</span><span class="kw">const</span> context<span class="op">&amp;)</span>;</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>  context ctx;</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>  ex<span class="op">::</span>counting_scope scope;</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>  ex<span class="op">::</span>sender <span class="kw">auto</span> snd <span class="op">=</span> work<span class="op">(</span>ctx<span class="op">)</span>;</span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span> </span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a>      <span class="co">// fire, but don&#39;t forget</span></span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a>      ex<span class="op">::</span>spawn<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>snd<span class="op">)</span>, scope<span class="op">.</span>get_token<span class="op">())</span>;</span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> <span class="cf">catch</span> <span class="op">(...)</span> <span class="op">{</span></span>
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a>      <span class="co">// do something to handle exception</span></span>
<span id="cb7-17"><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb7-18"><a href="#cb7-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-19"><a href="#cb7-19" aria-hidden="true" tabindex="-1"></a>  <span class="co">// wait for all work nested within scope</span></span>
<span id="cb7-20"><a href="#cb7-20" aria-hidden="true" tabindex="-1"></a>  <span class="co">// to finish</span></span>
<span id="cb7-21"><a href="#cb7-21" aria-hidden="true" tabindex="-1"></a>  this_thread<span class="op">::</span>sync_wait<span class="op">(</span>scope<span class="op">.</span>join<span class="op">())</span>;</span>
<span id="cb7-22"><a href="#cb7-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-23"><a href="#cb7-23" aria-hidden="true" tabindex="-1"></a>  <span class="co">// `ctx` is destroyed once nothing</span></span>
<span id="cb7-24"><a href="#cb7-24" aria-hidden="true" tabindex="-1"></a>  <span class="co">// references it</span></span>
<span id="cb7-25"><a href="#cb7-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

</div></td>
<td><div>

<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> ex <span class="op">=</span> std<span class="op">::</span>execution;</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> context;</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>ex<span class="op">::</span>sender <span class="kw">auto</span> work<span class="op">(</span><span class="kw">const</span> context<span class="op">&amp;)</span>;</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>  context ctx;</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>  this_thread<span class="op">::</span>sync_wait<span class="op">(</span>ex<span class="op">::</span>just<span class="op">()</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>      <span class="op">|</span> ex<span class="op">::</span>let_with_async_scope<span class="op">([&amp;](</span><span class="kw">auto</span> scope<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>        ex<span class="op">::</span>sender <span class="kw">auto</span> snd <span class="op">=</span> work<span class="op">(</span>ctx<span class="op">)</span>;</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>        <span class="co">// fire, but don&#39;t forget</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a>        ex<span class="op">::</span>spawn<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>snd<span class="op">)</span>, scope<span class="op">.</span>get_token<span class="op">())</span>;</span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a>      <span class="op">}))</span>;</span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a>  <span class="co">// `ctx` is destroyed once nothing</span></span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a>  <span class="co">// references it</span></span>
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

</div></td>
</tr>
</tbody>
</table>
<p>Please see below for more examples.</p>
<h2 data-number="3.2" id="counting_scope-and-let_with_async_scope-are-a-step-forward-towards-structured-concurrency"><span class="header-section-number">3.2</span>
<code class="sourceCode default">counting_scope</code> and
<code class="sourceCode default">let_with_async_scope</code> are a step
forward towards Structured Concurrency<a href="#counting_scope-and-let_with_async_scope-are-a-step-forward-towards-structured-concurrency" class="self-link"></a></h2>
<p>Structured Programming <span class="citation" data-cites="Dahl72">[<a href="#ref-Dahl72" role="doc-biblioref">Dahl72</a>]</span> transformed
the software world by making it easier to reason about the code, and
build large software from simpler constructs. We want to achieve the
same effect on concurrent programming by ensuring that we
<em>structure</em> our concurrent code. <span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span> makes a big step in that
direction, but, by itself, it doesn’t fully realize the principles of
Structured Programming. More specifically, it doesn’t always ensure that
we can apply the <em>single entry, single exit point</em> principle.</p>
<p>The <code class="sourceCode default">start_detached</code> sender
algorithm fails this principle by behaving like a
<code class="sourceCode default">GOTO</code> instruction. By calling
<code class="sourceCode default">start_detached</code> we essentially
continue in two places: in the same function, and on different thread
that executes the given work. Moreover, the lifetime of the work started
by <code class="sourceCode default">start_detached</code> cannot be
bound to the local context. This will prevent local reasoning, which
will make the program harder to understand.</p>
<p>To properly structure our concurrency, we need an abstraction that
ensures that all async work that is spawned has a defined, observable,
and controllable lifetime. This is the goal of
<code class="sourceCode default">counting_scope</code> and
<code class="sourceCode default">let_with_async_scope</code>.</p>
<h1 data-number="4" id="examples-of-use"><span class="header-section-number">4</span> Examples of use<a href="#examples-of-use" class="self-link"></a></h1>
<h2 data-number="4.1" id="spawning-work-from-within-a-task"><span class="header-section-number">4.1</span> Spawning work from within a
task<a href="#spawning-work-from-within-a-task" class="self-link"></a></h2>
<p>Use <code class="sourceCode default">let_with_async_scope</code> in
combination with a
<code class="sourceCode default">system_context</code> from <span class="citation" data-cites="P2079R2">[<a href="#ref-P2079R2" role="doc-biblioref">P2079R2</a>]</span> to spawn work from within a
task:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> ex <span class="op">=</span> std<span class="op">::</span>execution;</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>system_context ctx;</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> result <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>scheduler <span class="kw">auto</span> sch <span class="op">=</span> ctx<span class="op">.</span>scheduler<span class="op">()</span>;</span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>sender <span class="kw">auto</span> val <span class="op">=</span> ex<span class="op">::</span>just<span class="op">()</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>        <span class="op">|</span> ex<span class="op">::</span>let_with_async_scope<span class="op">([</span>sch<span class="op">](</span>ex<span class="op">::</span>async_scope_token <span class="kw">auto</span> scope<span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a>          <span class="dt">int</span> val <span class="op">=</span> <span class="dv">13</span>;</span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a>          <span class="kw">auto</span> print_sender <span class="op">=</span> ex<span class="op">::</span>just<span class="op">()</span></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a>              <span class="op">|</span> ex<span class="op">::</span>then<span class="op">([</span>val<span class="op">]()</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a>                std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;Hello world! Have an int with value: &quot;</span> <span class="op">&lt;&lt;</span> val <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a>              <span class="op">})</span>;</span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a>          <span class="co">// spawn the print sender on sch</span></span>
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a>          <span class="co">//</span></span>
<span id="cb9-20"><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a>          <span class="co">// </span><span class="al">NOTE</span><span class="co">: if spawn throws, let_with_async_scope will capture the exception</span></span>
<span id="cb9-21"><a href="#cb9-21" aria-hidden="true" tabindex="-1"></a>          <span class="co">//       and propagate it through its set_error completion</span></span>
<span id="cb9-22"><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a>          ex<span class="op">::</span>spawn<span class="op">(</span>ex<span class="op">::</span>on<span class="op">(</span>sch, std<span class="op">::</span>move<span class="op">(</span>print_sender<span class="op">))</span>, scope<span class="op">)</span>;</span>
<span id="cb9-23"><a href="#cb9-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-24"><a href="#cb9-24" aria-hidden="true" tabindex="-1"></a>          <span class="cf">return</span> ex<span class="op">::</span>just<span class="op">(</span>val<span class="op">)</span>;</span>
<span id="cb9-25"><a href="#cb9-25" aria-hidden="true" tabindex="-1"></a>        <span class="op">}))</span></span>
<span id="cb9-26"><a href="#cb9-26" aria-hidden="true" tabindex="-1"></a>        <span class="op">|</span> ex<span class="op">::</span>then<span class="op">([&amp;</span>result<span class="op">](</span><span class="kw">auto</span> val<span class="op">)</span> <span class="op">{</span> result <span class="op">=</span> val <span class="op">})</span>;</span>
<span id="cb9-27"><a href="#cb9-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-28"><a href="#cb9-28" aria-hidden="true" tabindex="-1"></a>    this_thread<span class="op">::</span>sync_wait<span class="op">(</span>ex<span class="op">::</span>on<span class="op">(</span>sch, std<span class="op">::</span>move<span class="op">(</span>val<span class="op">)))</span>;</span>
<span id="cb9-29"><a href="#cb9-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-30"><a href="#cb9-30" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;Result: &quot;</span> <span class="op">&lt;&lt;</span> result <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb9-31"><a href="#cb9-31" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb9-32"><a href="#cb9-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-33"><a href="#cb9-33" aria-hidden="true" tabindex="-1"></a><span class="co">// &#39;let_with_async_scope&#39; ensures that, if all work is completed successfully, the result will be 13</span></span>
<span id="cb9-34"><a href="#cb9-34" aria-hidden="true" tabindex="-1"></a><span class="co">// `sync_wait` will throw whatever exception is thrown by the callable passed to `let_with_async_scope`</span></span></code></pre></div>
<h2 data-number="4.2" id="starting-work-nested-within-a-framework"><span class="header-section-number">4.2</span> Starting work nested within a
framework<a href="#starting-work-nested-within-a-framework" class="self-link"></a></h2>
<p>In this example we use the
<code class="sourceCode default">counting_scope</code> within a class to
start work when the object receives a message and to wait for that work
to complete before closing.</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> ex <span class="op">=</span> std<span class="op">::</span>execution;</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> my_window <span class="op">{</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">class</span> close_message <span class="op">{}</span>;</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>sender <span class="kw">auto</span> some_work<span class="op">(</span><span class="dt">int</span> message<span class="op">)</span>;</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>sender <span class="kw">auto</span> some_work<span class="op">(</span>close_message message<span class="op">)</span>;</span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> onMessage<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a>        <span class="op">++</span>count;</span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>        ex<span class="op">::</span>spawn<span class="op">(</span>ex<span class="op">::</span>on<span class="op">(</span>sch, some_work<span class="op">(</span>i<span class="op">))</span>, scope<span class="op">)</span>;</span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> onClickClose<span class="op">()</span> <span class="op">{</span></span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a>        <span class="op">++</span>count;</span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a>        ex<span class="op">::</span>spawn<span class="op">(</span>ex<span class="op">::</span>on<span class="op">(</span>sch, some_work<span class="op">(</span>close_message<span class="op">{}))</span>, scope<span class="op">)</span>;</span>
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-20"><a href="#cb10-20" aria-hidden="true" tabindex="-1"></a>    my_window<span class="op">(</span>ex<span class="op">::</span>system_scheduler sch, ex<span class="op">::</span>counting_scope<span class="op">::</span>token scope<span class="op">)</span></span>
<span id="cb10-21"><a href="#cb10-21" aria-hidden="true" tabindex="-1"></a>      <span class="op">:</span> sch<span class="op">(</span>sch<span class="op">)</span>, scope<span class="op">(</span>scope<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-22"><a href="#cb10-22" aria-hidden="true" tabindex="-1"></a>      <span class="co">// register this window with the windowing framework somehow so that</span></span>
<span id="cb10-23"><a href="#cb10-23" aria-hidden="true" tabindex="-1"></a>      <span class="co">// it starts receiving calls to onClickClose() and onMessage()</span></span>
<span id="cb10-24"><a href="#cb10-24" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-25"><a href="#cb10-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-26"><a href="#cb10-26" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>system_scheduler sch;</span>
<span id="cb10-27"><a href="#cb10-27" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>counting_scope<span class="op">::</span>token scope;</span>
<span id="cb10-28"><a href="#cb10-28" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> count<span class="op">{</span><span class="dv">0</span><span class="op">}</span>;</span>
<span id="cb10-29"><a href="#cb10-29" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb10-30"><a href="#cb10-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-31"><a href="#cb10-31" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb10-32"><a href="#cb10-32" aria-hidden="true" tabindex="-1"></a>    <span class="co">// keep track of all spawned work</span></span>
<span id="cb10-33"><a href="#cb10-33" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>counting_scope scope;</span>
<span id="cb10-34"><a href="#cb10-34" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>system_context ctx;</span>
<span id="cb10-35"><a href="#cb10-35" aria-hidden="true" tabindex="-1"></a>    <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb10-36"><a href="#cb10-36" aria-hidden="true" tabindex="-1"></a>        my_window window<span class="op">{</span>ctx<span class="op">.</span>get_scheduler<span class="op">()</span>, scope<span class="op">.</span>get_token<span class="op">()}</span>;</span>
<span id="cb10-37"><a href="#cb10-37" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="cf">catch</span> <span class="op">(...)</span> <span class="op">{</span></span>
<span id="cb10-38"><a href="#cb10-38" aria-hidden="true" tabindex="-1"></a>      <span class="co">// do something with exception</span></span>
<span id="cb10-39"><a href="#cb10-39" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-40"><a href="#cb10-40" aria-hidden="true" tabindex="-1"></a>    <span class="co">// wait for all work nested within scope to finish</span></span>
<span id="cb10-41"><a href="#cb10-41" aria-hidden="true" tabindex="-1"></a>    this_thread<span class="op">::</span>sync_wait<span class="op">(</span>scope<span class="op">.</span>join<span class="op">())</span>;</span>
<span id="cb10-42"><a href="#cb10-42" aria-hidden="true" tabindex="-1"></a>    <span class="co">// all resources are now safe to destroy</span></span>
<span id="cb10-43"><a href="#cb10-43" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> window<span class="op">.</span>count;</span>
<span id="cb10-44"><a href="#cb10-44" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="4.3" id="starting-parallel-work"><span class="header-section-number">4.3</span> Starting parallel work<a href="#starting-parallel-work" class="self-link"></a></h2>
<p>In this example we use
<code class="sourceCode default">let_with_async_scope</code> to
construct an algorithm that performs parallel work. Here
<code class="sourceCode default">foo</code> launches 100 tasks that
concurrently run on some scheduler provided to
<code class="sourceCode default">foo</code>, through its connected
receiver, and then the tasks are asynchronously joined. This structure
emulates how we might build a parallel algorithm where each
<code class="sourceCode default">some_work</code> might be operating on
a fragment of data.</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> ex <span class="op">=</span> std<span class="op">::</span>execution;</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>ex<span class="op">::</span>sender <span class="kw">auto</span> some_work<span class="op">(</span><span class="dt">int</span> work_index<span class="op">)</span>;</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>ex<span class="op">::</span>sender <span class="kw">auto</span> foo<span class="op">(</span>ex<span class="op">::</span>scheduler <span class="kw">auto</span> sch<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> ex<span class="op">::</span>just<span class="op">()</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>      <span class="op">|</span> ex<span class="op">::</span>let_with_async_scope<span class="op">([</span>sch<span class="op">](</span>ex<span class="op">::</span>async_scope_token <span class="kw">auto</span> scope<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> ex<span class="op">::</span>schedule<span class="op">(</span>sch<span class="op">)</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>            <span class="op">|</span> ex<span class="op">::</span>then<span class="op">([]</span> <span class="op">{</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>              std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;Before tasks launch</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>            <span class="op">})</span></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>            <span class="op">|</span> ex<span class="op">::</span>then<span class="op">([=]</span> <span class="op">{</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>              <span class="co">// Create parallel work</span></span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>              <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> <span class="dv">100</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a>                <span class="co">// </span><span class="al">NOTE</span><span class="co">: if spawn() throws, the exception will be propagated as the</span></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a>                <span class="co">//       result of let_with_async_scope through its set_error completion</span></span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a>                ex<span class="op">::</span>spawn<span class="op">(</span>ex<span class="op">::</span>on<span class="op">(</span>sch, some_work<span class="op">(</span>i<span class="op">))</span>, scope<span class="op">)</span>;</span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a>              <span class="op">}</span></span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a>            <span class="op">})</span>;</span>
<span id="cb11-20"><a href="#cb11-20" aria-hidden="true" tabindex="-1"></a>      <span class="op">})</span></span>
<span id="cb11-21"><a href="#cb11-21" aria-hidden="true" tabindex="-1"></a>      <span class="op">|</span> ex<span class="op">::</span>then<span class="op">([]</span> <span class="op">{</span> std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;After tasks complete successfully</span><span class="sc">\n</span><span class="st">&quot;</span>; <span class="op">})</span>;</span>
<span id="cb11-22"><a href="#cb11-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="4.4" id="listener-loop-in-an-http-server"><span class="header-section-number">4.4</span> Listener loop in an HTTP
server<a href="#listener-loop-in-an-http-server" class="self-link"></a></h2>
<p>This example shows how one can write the listener loop in an HTTP
server, with the help of coroutines. The HTTP server will continuously
accept new connection and start work to handle the requests coming on
the new connections. While the listening activity is bound in the scope
of the loop, the lifetime of handling requests may exceed the scope of
the loop. We use <code class="sourceCode default">counting_scope</code>
to limit the lifetime of the request handling without blocking the
acceptance of new requests.</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> ex <span class="op">=</span> std<span class="op">::</span>execution;</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>task<span class="op">&lt;</span><span class="dt">size_t</span><span class="op">&gt;</span> listener<span class="op">(</span><span class="dt">int</span> port, io_context<span class="op">&amp;</span> ctx, static_thread_pool<span class="op">&amp;</span> pool<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">size_t</span> count<span class="op">{</span><span class="dv">0</span><span class="op">}</span>;</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>    listening_socket listen_sock<span class="op">{</span>port<span class="op">}</span>;</span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">co_await</span> ex<span class="op">::</span>let_with_async_scope<span class="op">(</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>        ex<span class="op">::</span>just<span class="op">()</span>, <span class="op">[&amp;](</span>ex<span class="op">::</span>async_scope_token <span class="kw">auto</span> scope<span class="op">)</span> <span class="op">-&gt;</span> task<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>          <span class="cf">while</span> <span class="op">(!</span>ctx<span class="op">.</span>is_stopped<span class="op">())</span> <span class="op">{</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>            <span class="co">// Accept a new connection</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>            connection conn <span class="op">=</span> <span class="kw">co_await</span> async_accept<span class="op">(</span>ctx, listen_sock<span class="op">)</span>;</span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a>            count<span class="op">++</span>;</span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a>            <span class="co">// Create work to handle the connection in the scope of `work_scope`</span></span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a>            conn_data data<span class="op">{</span>std<span class="op">::</span>move<span class="op">(</span>conn<span class="op">)</span>, ctx, pool<span class="op">}</span>;</span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a>            ex<span class="op">::</span>sender <span class="kw">auto</span> snd <span class="op">=</span> ex<span class="op">::</span>just<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>data<span class="op">))</span></span>
<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a>                <span class="op">|</span> ex<span class="op">::</span>let_value<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;</span> data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a>                  <span class="cf">return</span> handle_connection<span class="op">(</span>data<span class="op">)</span>;</span>
<span id="cb12-19"><a href="#cb12-19" aria-hidden="true" tabindex="-1"></a>                <span class="op">})</span>;</span>
<span id="cb12-20"><a href="#cb12-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-21"><a href="#cb12-21" aria-hidden="true" tabindex="-1"></a>            ex<span class="op">::</span>spawn<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>snd<span class="op">)</span>, scope<span class="op">)</span>;</span>
<span id="cb12-22"><a href="#cb12-22" aria-hidden="true" tabindex="-1"></a>          <span class="op">}</span></span>
<span id="cb12-23"><a href="#cb12-23" aria-hidden="true" tabindex="-1"></a>        <span class="op">})</span>;</span>
<span id="cb12-24"><a href="#cb12-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-25"><a href="#cb12-25" aria-hidden="true" tabindex="-1"></a>    <span class="co">// At this point, all the request handling is complete</span></span>
<span id="cb12-26"><a href="#cb12-26" aria-hidden="true" tabindex="-1"></a>    <span class="kw">co_return</span> count;</span>
<span id="cb12-27"><a href="#cb12-27" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><span class="citation" data-cites="libunifex">[<a href="#ref-libunifex" role="doc-biblioref">libunifex</a>]</span> has a
very similar example HTTP server at <span class="citation" data-cites="iouringserver">[<a href="#ref-iouringserver" role="doc-biblioref">io_uring HTTP server</a>]</span> that compiles and
runs on Linux-based machines with
<code class="sourceCode default">io_uring</code> support.</p>
<h2 data-number="4.5" id="pluggable-functionality-through-composition"><span class="header-section-number">4.5</span> Pluggable functionality through
composition<a href="#pluggable-functionality-through-composition" class="self-link"></a></h2>
<p>This example is based on real code in rsys, but it reduces the real
code to slideware and ports it from Unifex to the proposed
<code class="sourceCode default">std::execution</code> equivalents. The
central abstraction in rsys is a
<code class="sourceCode default">Call</code>, but each integration of
rsys has different needs so the set of features supported by a
<code class="sourceCode default">Call</code> varies with the build
configuration. We support this configurability by exposing the
equivalent of the following method on the
<code class="sourceCode default">Call</code> class:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Feature<span class="op">&gt;</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>Handle<span class="op">&lt;</span>Feature<span class="op">&gt;</span> Call<span class="op">::</span>get<span class="op">()</span>;</span></code></pre></div>
<p>and it’s used like this in app-layer code:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>unifex<span class="op">::</span>task<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;</span> maybeToggleCamera<span class="op">(</span>Call<span class="op">&amp;</span> call<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>  Handle<span class="op">&lt;</span>Camera<span class="op">&gt;</span> camera <span class="op">=</span> call<span class="op">.</span>get<span class="op">&lt;</span>Camera<span class="op">&gt;()</span>;</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>camera<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">co_await</span> camera<span class="op">-&gt;</span>toggle<span class="op">()</span>;</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>A <code class="sourceCode default">Handle&lt;Feature&gt;</code> is
effectively a part-owner of the
<code class="sourceCode default">Call</code> it came from.</p>
<p>The team that maintains rsys and the teams that use rsys are,
unsurprisingly, different teams so rsys has to be designed to solve
organizational problems as well as technical problems. One relevant
design decision the rsys team made is that it is safe to keep using a
<code class="sourceCode default">Handle&lt;Feature&gt;</code> after the
end of its <code class="sourceCode default">Call</code>’s lifetime; this
choice adds some complexity to the design of
<code class="sourceCode default">Call</code> and its various features
but it also simplifies the support relationship between the rsys team
and its many partner teams because it eliminates many crash-at-shutdown
bugs.</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> rsys <span class="op">{</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Call <span class="op">{</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span><span class="op">:</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>  unifex<span class="op">::</span>nothrow_task<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;</span> destroy<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">// first, close the scope to new work and wait for existing work to finish</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>    scope_<span class="op">-&gt;</span>close<span class="op">()</span>;</span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">co_await</span> scope_<span class="op">-&gt;</span>join<span class="op">()</span>;</span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a>    <span class="co">// other clean-up tasks here</span></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Feature<span class="op">&gt;</span></span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a>  Handle<span class="op">&lt;</span>Feature<span class="op">&gt;</span> get<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-16"><a href="#cb15-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span><span class="op">:</span></span>
<span id="cb15-17"><a href="#cb15-17" aria-hidden="true" tabindex="-1"></a>  <span class="co">// an async scope shared between a call and its features</span></span>
<span id="cb15-18"><a href="#cb15-18" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>shared_ptr<span class="op">&lt;</span>std<span class="op">::</span>execution<span class="op">::</span>counting_scope<span class="op">&gt;</span> scope_;</span>
<span id="cb15-19"><a href="#cb15-19" aria-hidden="true" tabindex="-1"></a>  <span class="co">// each call has its own set of threads</span></span>
<span id="cb15-20"><a href="#cb15-20" aria-hidden="true" tabindex="-1"></a>  ExecutionContext context_;</span>
<span id="cb15-21"><a href="#cb15-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-22"><a href="#cb15-22" aria-hidden="true" tabindex="-1"></a>  <span class="co">// the set of features this call supports</span></span>
<span id="cb15-23"><a href="#cb15-23" aria-hidden="true" tabindex="-1"></a>  FeatureBag features_;</span>
<span id="cb15-24"><a href="#cb15-24" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb15-25"><a href="#cb15-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-26"><a href="#cb15-26" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Camera <span class="op">{</span></span>
<span id="cb15-27"><a href="#cb15-27" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span><span class="op">:</span></span>
<span id="cb15-28"><a href="#cb15-28" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>execution<span class="op">::</span>sender <span class="kw">auto</span> toggle<span class="op">()</span> <span class="op">{</span></span>
<span id="cb15-29"><a href="#cb15-29" aria-hidden="true" tabindex="-1"></a>    <span class="kw">namespace</span> ex <span class="op">=</span> std<span class="op">::</span>execution;</span>
<span id="cb15-30"><a href="#cb15-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-31"><a href="#cb15-31" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> ex<span class="op">::</span>just<span class="op">()</span> <span class="op">|</span> ex<span class="op">::</span>let_value<span class="op">([</span><span class="kw">this</span><span class="op">]()</span> <span class="op">{</span></span>
<span id="cb15-32"><a href="#cb15-32" aria-hidden="true" tabindex="-1"></a>      <span class="co">// this callable is only invoked if the Call&#39;s scope is in</span></span>
<span id="cb15-33"><a href="#cb15-33" aria-hidden="true" tabindex="-1"></a>      <span class="co">// the open or unused state when nest() is invoked, making</span></span>
<span id="cb15-34"><a href="#cb15-34" aria-hidden="true" tabindex="-1"></a>      <span class="co">// it safe to assume here that:</span></span>
<span id="cb15-35"><a href="#cb15-35" aria-hidden="true" tabindex="-1"></a>      <span class="co">//</span></span>
<span id="cb15-36"><a href="#cb15-36" aria-hidden="true" tabindex="-1"></a>      <span class="co">//  - scheduler_ is not a dangling reference to the call&#39;s</span></span>
<span id="cb15-37"><a href="#cb15-37" aria-hidden="true" tabindex="-1"></a>      <span class="co">//    execution context</span></span>
<span id="cb15-38"><a href="#cb15-38" aria-hidden="true" tabindex="-1"></a>      <span class="co">//  - Call::destroy() has not progressed past starting the</span></span>
<span id="cb15-39"><a href="#cb15-39" aria-hidden="true" tabindex="-1"></a>      <span class="co">//    join-sender so all the resources owned by the call</span></span>
<span id="cb15-40"><a href="#cb15-40" aria-hidden="true" tabindex="-1"></a>      <span class="co">//    are still valid</span></span>
<span id="cb15-41"><a href="#cb15-41" aria-hidden="true" tabindex="-1"></a>      <span class="co">//</span></span>
<span id="cb15-42"><a href="#cb15-42" aria-hidden="true" tabindex="-1"></a>      <span class="co">// if the nest() attempt fails because the join-sender has</span></span>
<span id="cb15-43"><a href="#cb15-43" aria-hidden="true" tabindex="-1"></a>      <span class="co">// started (or even if the Call has been completely destroyed)</span></span>
<span id="cb15-44"><a href="#cb15-44" aria-hidden="true" tabindex="-1"></a>      <span class="co">// then the sender returned from toggle() will safely do</span></span>
<span id="cb15-45"><a href="#cb15-45" aria-hidden="true" tabindex="-1"></a>      <span class="co">// nothing before completing with set_stopped()</span></span>
<span id="cb15-46"><a href="#cb15-46" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-47"><a href="#cb15-47" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> ex<span class="op">::</span>schedule<span class="op">(</span>scheduler_<span class="op">)</span> <span class="op">|</span> ex<span class="op">::</span>then<span class="op">([</span><span class="kw">this</span><span class="op">]()</span> <span class="op">{</span></span>
<span id="cb15-48"><a href="#cb15-48" aria-hidden="true" tabindex="-1"></a>        <span class="co">// toggle the camera</span></span>
<span id="cb15-49"><a href="#cb15-49" aria-hidden="true" tabindex="-1"></a>      <span class="op">})</span>;</span>
<span id="cb15-50"><a href="#cb15-50" aria-hidden="true" tabindex="-1"></a>    <span class="op">})</span> <span class="op">|</span> ex<span class="op">::</span>nest<span class="op">(</span>callScope_<span class="op">-&gt;</span>get_token<span class="op">())</span>;</span>
<span id="cb15-51"><a href="#cb15-51" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb15-52"><a href="#cb15-52" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-53"><a href="#cb15-53" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span><span class="op">:</span></span>
<span id="cb15-54"><a href="#cb15-54" aria-hidden="true" tabindex="-1"></a>  <span class="co">// a copy of this camera&#39;s Call&#39;s scope_ member</span></span>
<span id="cb15-55"><a href="#cb15-55" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>shared_ptr<span class="op">&lt;</span>ex<span class="op">::</span>counting_scope<span class="op">&gt;</span> callScope_;</span>
<span id="cb15-56"><a href="#cb15-56" aria-hidden="true" tabindex="-1"></a>  <span class="co">// a scheduler that refers to this camera&#39;s Call&#39;s ExecutionContext</span></span>
<span id="cb15-57"><a href="#cb15-57" aria-hidden="true" tabindex="-1"></a>  Scheduler scheduler_;</span>
<span id="cb15-58"><a href="#cb15-58" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb15-59"><a href="#cb15-59" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-60"><a href="#cb15-60" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="4.6" id="recursively-spawning-work-until-completion"><span class="header-section-number">4.6</span> Recursively spawning work until
completion<a href="#recursively-spawning-work-until-completion" class="self-link"></a></h2>
<p>Below are three ways you could recursively spawn work on a scope
using <code class="sourceCode default">let_with_async_scope</code> or
<code class="sourceCode default">counting_scope</code>.</p>
<h3 data-number="4.6.1" id="let_with_async_scope-with-spawn"><span class="header-section-number">4.6.1</span>
<code class="sourceCode default">let_with_async_scope</code> with
<code class="sourceCode default">spawn()</code><a href="#let_with_async_scope-with-spawn" class="self-link"></a></h3>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> tree <span class="op">{</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>unique_ptr<span class="op">&lt;</span>tree<span class="op">&gt;</span> left;</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>unique_ptr<span class="op">&lt;</span>tree<span class="op">&gt;</span> right;</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> data;</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> process<span class="op">(</span>ex<span class="op">::</span>scheduler <span class="kw">auto</span> sch, <span class="kw">auto</span> scope, tree<span class="op">&amp;</span> t<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> ex<span class="op">::</span>schedule<span class="op">(</span>sch<span class="op">)</span> <span class="op">|</span> then<span class="op">([</span>sch, <span class="op">&amp;]()</span> <span class="op">{</span></span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>t<span class="op">.</span>left<span class="op">)</span></span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a>      ex<span class="op">::</span>spawn<span class="op">(</span>process<span class="op">(</span>sch, scope, t<span class="op">.</span>left<span class="op">.</span>get<span class="op">())</span>, scope<span class="op">)</span>;</span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>t<span class="op">.</span>right<span class="op">)</span></span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a>      ex<span class="op">::</span>spawn<span class="op">(</span>process<span class="op">(</span>sch, scope, t<span class="op">.</span>right<span class="op">.</span>get<span class="op">())</span>, scope<span class="op">)</span>;</span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a>    do_stuff<span class="op">(</span>t<span class="op">.</span>data<span class="op">)</span>;</span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">})</span> <span class="op">|</span> ex<span class="op">::</span>let_error<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a>    <span class="co">// log error</span></span>
<span id="cb16-16"><a href="#cb16-16" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> just<span class="op">()</span>;</span>
<span id="cb16-17"><a href="#cb16-17" aria-hidden="true" tabindex="-1"></a>  <span class="op">})</span>;</span>
<span id="cb16-18"><a href="#cb16-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb16-19"><a href="#cb16-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-20"><a href="#cb16-20" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb16-21"><a href="#cb16-21" aria-hidden="true" tabindex="-1"></a>  ex<span class="op">::</span>scheduler sch;</span>
<span id="cb16-22"><a href="#cb16-22" aria-hidden="true" tabindex="-1"></a>  tree t <span class="op">=</span> make_tree<span class="op">()</span>;</span>
<span id="cb16-23"><a href="#cb16-23" aria-hidden="true" tabindex="-1"></a>  <span class="co">// let_with_async_scope will ensure all new work will be spawned on the</span></span>
<span id="cb16-24"><a href="#cb16-24" aria-hidden="true" tabindex="-1"></a>  <span class="co">// scope and will not be joined until all work is finished.</span></span>
<span id="cb16-25"><a href="#cb16-25" aria-hidden="true" tabindex="-1"></a>  <span class="co">// </span><span class="al">NOTE</span><span class="co">: Exceptions will not be surfaced to let_with_async_scope; exceptions</span></span>
<span id="cb16-26"><a href="#cb16-26" aria-hidden="true" tabindex="-1"></a>  <span class="co">// will be handled by let_error instead.</span></span>
<span id="cb16-27"><a href="#cb16-27" aria-hidden="true" tabindex="-1"></a>  this_thread<span class="op">::</span>sync_wait<span class="op">(</span>ex<span class="op">::</span>let_with_async_scope<span class="op">([&amp;</span>, sch<span class="op">](</span><span class="kw">auto</span> scope<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-28"><a href="#cb16-28" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> process<span class="op">(</span>sch, scope, t<span class="op">)</span>;</span>
<span id="cb16-29"><a href="#cb16-29" aria-hidden="true" tabindex="-1"></a>  <span class="op">}))</span>;</span>
<span id="cb16-30"><a href="#cb16-30" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="4.6.2" id="let_with_async_scope-with-spawn_future"><span class="header-section-number">4.6.2</span>
<code class="sourceCode default">let_with_async_scope</code> with
<code class="sourceCode default">spawn_future()</code><a href="#let_with_async_scope-with-spawn_future" class="self-link"></a></h3>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> tree <span class="op">{</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>unique_ptr<span class="op">&lt;</span>tree<span class="op">&gt;</span> left;</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>unique_ptr<span class="op">&lt;</span>tree<span class="op">&gt;</span> right;</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> data;</span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> process<span class="op">(</span>ex<span class="op">::</span>scheduler <span class="kw">auto</span> sch, <span class="kw">auto</span> scope, tree<span class="op">&amp;</span> t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> ex<span class="op">::</span>schedule<span class="op">(</span>sch<span class="op">)</span> <span class="op">|</span> ex<span class="op">::</span>let_value<span class="op">([</span>sch, <span class="op">&amp;]()</span> <span class="op">{</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a>      unifex<span class="op">::</span>any_sender_of<span class="op">&lt;&gt;</span> leftFut <span class="op">=</span> ex<span class="op">::</span>just<span class="op">()</span>;</span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>      unifex<span class="op">::</span>any_sender_of<span class="op">&lt;&gt;</span> rightFut <span class="op">=</span> ex<span class="op">::</span>just<span class="op">()</span>;</span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>      <span class="cf">if</span> <span class="op">(</span>t<span class="op">.</span>left<span class="op">)</span> <span class="op">{</span>  </span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>         leftFut <span class="op">=</span> ex<span class="op">::</span>spawn_future<span class="op">(</span></span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a>         scope, process<span class="op">(</span>sch, scope, t<span class="op">.</span>left<span class="op">.</span>get<span class="op">()))</span>;</span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a>      <span class="cf">if</span> <span class="op">(</span>t<span class="op">.</span>right<span class="op">)</span> <span class="op">{</span> </span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a>         rightFut <span class="op">=</span> ex<span class="op">::</span>spawn_future<span class="op">(</span></span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true" tabindex="-1"></a>         scope, process<span class="op">(</span>sch, scope, t<span class="op">.</span>right<span class="op">.</span>get<span class="op">()))</span>;</span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-21"><a href="#cb17-21" aria-hidden="true" tabindex="-1"></a>      do_stuff<span class="op">(</span>t<span class="op">.</span>data<span class="op">)</span>;</span>
<span id="cb17-22"><a href="#cb17-22" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> ex<span class="op">::</span>when_all<span class="op">(</span>leftFut, rightFut<span class="op">)</span> <span class="op">|</span> ex<span class="op">::</span>then<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;&amp;...)</span> <span class="kw">noexcept</span> <span class="op">{})</span>;</span>
<span id="cb17-23"><a href="#cb17-23" aria-hidden="true" tabindex="-1"></a>    <span class="op">})</span>;</span>
<span id="cb17-24"><a href="#cb17-24" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb17-25"><a href="#cb17-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-26"><a href="#cb17-26" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb17-27"><a href="#cb17-27" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>scheduler sch;</span>
<span id="cb17-28"><a href="#cb17-28" aria-hidden="true" tabindex="-1"></a>    tree t <span class="op">=</span> make_tree<span class="op">()</span>;</span>
<span id="cb17-29"><a href="#cb17-29" aria-hidden="true" tabindex="-1"></a>    <span class="co">// let_with_async_scope will ensure all new work will be spawned on the</span></span>
<span id="cb17-30"><a href="#cb17-30" aria-hidden="true" tabindex="-1"></a>    <span class="co">// scope and will not be joined until all work is finished</span></span>
<span id="cb17-31"><a href="#cb17-31" aria-hidden="true" tabindex="-1"></a>    <span class="co">// </span><span class="al">NOTE</span><span class="co">: Exceptions will be surfaced to let_with_async_scope which will</span></span>
<span id="cb17-32"><a href="#cb17-32" aria-hidden="true" tabindex="-1"></a>    <span class="co">// call set_error with the exception_ptr</span></span>
<span id="cb17-33"><a href="#cb17-33" aria-hidden="true" tabindex="-1"></a>    this_thread<span class="op">::</span>sync_wait<span class="op">(</span>ex<span class="op">::</span>let_with_async_scope<span class="op">([&amp;</span>, sch<span class="op">](</span><span class="kw">auto</span> scope<span class="op">)</span> <span class="op">{</span> </span>
<span id="cb17-34"><a href="#cb17-34" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> process<span class="op">(</span>sch, scope, t<span class="op">)</span>;</span>
<span id="cb17-35"><a href="#cb17-35" aria-hidden="true" tabindex="-1"></a>    <span class="op">}))</span>;</span>
<span id="cb17-36"><a href="#cb17-36" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="4.6.3" id="counting_scope"><span class="header-section-number">4.6.3</span>
<code class="sourceCode default">counting_scope</code><a href="#counting_scope" class="self-link"></a></h3>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> tree <span class="op">{</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>unique_ptr<span class="op">&lt;</span>tree<span class="op">&gt;</span> left;</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>unique_ptr<span class="op">&lt;</span>tree<span class="op">&gt;</span> right;</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> data;</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> process<span class="op">(</span>ex<span class="op">::</span>counting_scope_token scope, ex<span class="op">::</span>scheduler <span class="kw">auto</span> sch, tree<span class="op">&amp;</span> t<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> ex<span class="op">::</span>schedule<span class="op">(</span>sch<span class="op">)</span> <span class="op">|</span> ex<span class="op">::</span>then<span class="op">([</span>sch, <span class="op">&amp;]()</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>t<span class="op">.</span>left<span class="op">)</span></span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a>       ex<span class="op">::</span>spawn<span class="op">(</span>process<span class="op">(</span>scope, sch, t<span class="op">.</span>left<span class="op">.</span>get<span class="op">())</span>, scope<span class="op">)</span>;</span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>t<span class="op">.</span>right<span class="op">)</span></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a>       ex<span class="op">::</span>spawn<span class="op">(</span>process<span class="op">(</span>scope, sch, t<span class="op">.</span>right<span class="op">.</span>get<span class="op">())</span>, scope<span class="op">)</span>;</span>
<span id="cb18-14"><a href="#cb18-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-15"><a href="#cb18-15" aria-hidden="true" tabindex="-1"></a>     do_stuff<span class="op">(</span>t<span class="op">.</span>data<span class="op">)</span>;</span>
<span id="cb18-16"><a href="#cb18-16" aria-hidden="true" tabindex="-1"></a>   <span class="op">})</span> <span class="op">|</span> ex<span class="op">::</span>let_error<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb18-17"><a href="#cb18-17" aria-hidden="true" tabindex="-1"></a>       <span class="co">// log error</span></span>
<span id="cb18-18"><a href="#cb18-18" aria-hidden="true" tabindex="-1"></a>       <span class="cf">return</span> just<span class="op">()</span>;</span>
<span id="cb18-19"><a href="#cb18-19" aria-hidden="true" tabindex="-1"></a>   <span class="op">})</span>;</span>
<span id="cb18-20"><a href="#cb18-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb18-21"><a href="#cb18-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-22"><a href="#cb18-22" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb18-23"><a href="#cb18-23" aria-hidden="true" tabindex="-1"></a>  ex<span class="op">::</span>scheduler sch;</span>
<span id="cb18-24"><a href="#cb18-24" aria-hidden="true" tabindex="-1"></a>  tree t <span class="op">=</span> make_tree<span class="op">()</span>;</span>
<span id="cb18-25"><a href="#cb18-25" aria-hidden="true" tabindex="-1"></a>  ex<span class="op">::</span>counting_scope scope;</span>
<span id="cb18-26"><a href="#cb18-26" aria-hidden="true" tabindex="-1"></a>  ex<span class="op">::</span>spawn<span class="op">(</span>process<span class="op">(</span>scope<span class="op">.</span>get_token<span class="op">()</span>, sch, t<span class="op">)</span>, scope<span class="op">.</span>get_token<span class="op">())</span>;</span>
<span id="cb18-27"><a href="#cb18-27" aria-hidden="true" tabindex="-1"></a>  this_thread<span class="op">::</span>sync_wait<span class="op">(</span>scope<span class="op">.</span>join<span class="op">())</span>;</span>
<span id="cb18-28"><a href="#cb18-28" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h1 data-number="5" id="async-scope-usage-guide"><span class="header-section-number">5</span> Async Scope, usage guide<a href="#async-scope-usage-guide" class="self-link"></a></h1>
<p>An async scope is a type that implements a “bookkeeping policy” for
senders that have been <code class="sourceCode default">nest()</code>ed
within the scope. Depending on the policy, different guarantees can be
provided in terms of the lifetimes of the scope and any nested senders.
The <code class="sourceCode default">counting_scope</code> described in
this paper defines a policy that has proven useful while progressively
adding structure to existing, unstructured code at Meta, but other
useful policies are possible. By defining
<code class="sourceCode default">spawn()</code> and
<code class="sourceCode default">spawn_future()</code> in terms of the
more fundamental <code class="sourceCode default">nest()</code>, and
leaving the definition of <code class="sourceCode default">nest()</code>
to the scope, this paper’s design leaves the set of policies open to
extension by user code or future standards.</p>
<p>An async scope’s implementation of
<code class="sourceCode default">nest()</code>:</p>
<ul>
<li>must allow an arbitrary sender to be nested within the scope without
eagerly starting the sender;</li>
<li>must not return a sender that adds new value or error completions to
the completions of the sender being nested;</li>
<li>may fail to nest a new sender by returning an “unnested” sender that
completes with <code class="sourceCode default">set_stopped</code> when
run without running the sender that failed to nest;</li>
<li>may fail to nest a new sender by eagerly throwing an exception
during the call to <code class="sourceCode default">nest()</code>;
and</li>
<li>is expected to be “cheap” like other sender adaptor objects.</li>
</ul>
<p>More on these items can be found below in the sections below.</p>
<h2 data-number="5.1" id="definitions"><span class="header-section-number">5.1</span> Definitions<a href="#definitions" class="self-link"></a></h2>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> <span class="op">{</span> <span class="co">// <em>exposition-only</em></span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>scope-token</em> <span class="op">{</span> <span class="co">// <em>exposition-only</em></span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span>sender Sender<span class="op">&gt;</span></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>  sender <span class="kw">auto</span> nest<span class="op">(</span>Sender<span class="op">&amp;&amp;</span> s<span class="op">)</span></span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a>      <span class="kw">noexcept</span><span class="op">(</span>is_nothrow_constructible_v<span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span>Sender<span class="op">&gt;</span>, Sender<span class="op">&gt;)</span>;</span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Env<span class="op">&gt;</span></span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>spawn-env</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Env<span class="op">&gt;</span></span>
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>spawn-receiver</em> <span class="op">{</span> <span class="co">// <em>exposition-only</em></span></span>
<span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> set_value<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb19-15"><a href="#cb19-15" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> set_stopped<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb19-16"><a href="#cb19-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-17"><a href="#cb19-17" aria-hidden="true" tabindex="-1"></a>    <em>spawn-env</em><span class="op">&lt;</span>Env<span class="op">&gt;</span> get_env<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb19-18"><a href="#cb19-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb19-19"><a href="#cb19-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-20"><a href="#cb19-20" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Env<span class="op">&gt;</span></span>
<span id="cb19-21"><a href="#cb19-21" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>future-env</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb19-22"><a href="#cb19-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-23"><a href="#cb19-23" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><em>valid-completion-signatures</em> Sigs<span class="op">&gt;</span></span>
<span id="cb19-24"><a href="#cb19-24" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>future-sender</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb19-25"><a href="#cb19-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-26"><a href="#cb19-26" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, <span class="kw">class</span> Env<span class="op">&gt;</span></span>
<span id="cb19-27"><a href="#cb19-27" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <em>future-sender-t</em> <span class="op">=</span> <span class="co">// <em>exposition-only</em></span></span>
<span id="cb19-28"><a href="#cb19-28" aria-hidden="true" tabindex="-1"></a>    <em>future-sender</em><span class="op">&lt;</span>completion_signatures_of_t<span class="op">&lt;</span>Sender, <em>future-env</em><span class="op">&lt;</span>Env<span class="op">&gt;&gt;&gt;</span>;</span>
<span id="cb19-29"><a href="#cb19-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-30"><a href="#cb19-30" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb19-31"><a href="#cb19-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-32"><a href="#cb19-32" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Token, <span class="kw">class</span> Sender<span class="op">&gt;</span></span>
<span id="cb19-33"><a href="#cb19-33" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> async_scope_token <span class="op">=</span></span>
<span id="cb19-34"><a href="#cb19-34" aria-hidden="true" tabindex="-1"></a>    copyable<span class="op">&lt;</span>Token<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb19-35"><a href="#cb19-35" aria-hidden="true" tabindex="-1"></a>    is_nothrow_move_constructible_v<span class="op">&lt;</span>Token<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb19-36"><a href="#cb19-36" aria-hidden="true" tabindex="-1"></a>    is_nothrow_move_assignable_v<span class="op">&lt;</span>Token<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb19-37"><a href="#cb19-37" aria-hidden="true" tabindex="-1"></a>    is_nothrow_copy_constructible_v<span class="op">&lt;</span>Token<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb19-38"><a href="#cb19-38" aria-hidden="true" tabindex="-1"></a>    is_nothrow_copy_assignable_v<span class="op">&lt;</span>Token<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb19-39"><a href="#cb19-39" aria-hidden="true" tabindex="-1"></a>    sender<span class="op">&lt;</span>Sender<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb19-40"><a href="#cb19-40" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span><span class="op">(</span>Token token, Sender<span class="op">&amp;&amp;</span> snd<span class="op">)</span> <span class="op">{</span></span>
<span id="cb19-41"><a href="#cb19-41" aria-hidden="true" tabindex="-1"></a>      <span class="op">{</span> token<span class="op">.</span>nest<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Sender<span class="op">&gt;(</span>snd<span class="op">))</span> <span class="op">}</span> <span class="op">-&gt;</span> sender;</span>
<span id="cb19-42"><a href="#cb19-42" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb19-43"><a href="#cb19-43" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-44"><a href="#cb19-44" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, async_scope_token<span class="op">&lt;</span>Sender<span class="op">&gt;</span> Token<span class="op">&gt;</span></span>
<span id="cb19-45"><a href="#cb19-45" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> nest<span class="op">(</span>Sender<span class="op">&amp;&amp;</span> snd, Token token<span class="op">)</span> <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span>token<span class="op">.</span>nest<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Sender<span class="op">&gt;(</span>snd<span class="op">))))</span></span>
<span id="cb19-46"><a href="#cb19-46" aria-hidden="true" tabindex="-1"></a>    <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span>token<span class="op">.</span>nest<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Sender<span class="op">&gt;(</span>snd<span class="op">)))</span>;</span>
<span id="cb19-47"><a href="#cb19-47" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-48"><a href="#cb19-48" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, async_scope_token<span class="op">&lt;</span>Sender<span class="op">&gt;</span> Token, <span class="kw">class</span> Env <span class="op">=</span> empty_env<span class="op">&gt;</span></span>
<span id="cb19-49"><a href="#cb19-49" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> sender_to<span class="op">&lt;</span>Sender, <em>spawn-receiver</em><span class="op">&lt;</span>Env<span class="op">&gt;&gt;</span></span>
<span id="cb19-50"><a href="#cb19-50" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> spawn<span class="op">(</span>Sender<span class="op">&amp;&amp;</span> snd, Token token, Env env <span class="op">=</span> <span class="op">{})</span>;</span>
<span id="cb19-51"><a href="#cb19-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-52"><a href="#cb19-52" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, async_scope_token<span class="op">&lt;</span>Sender<span class="op">&gt;</span> Token, <span class="kw">class</span> Env <span class="op">=</span> empty_env<span class="op">&gt;</span></span>
<span id="cb19-53"><a href="#cb19-53" aria-hidden="true" tabindex="-1"></a><em>future-sender-t</em><span class="op">&lt;</span>Sender, Env<span class="op">&gt;</span> spawn_future<span class="op">(</span>Sender<span class="op">&amp;&amp;</span> snd, Token token, Env env <span class="op">=</span> <span class="op">{})</span>;</span>
<span id="cb19-54"><a href="#cb19-54" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-55"><a href="#cb19-55" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> simple_counting_scope <span class="op">{</span></span>
<span id="cb19-56"><a href="#cb19-56" aria-hidden="true" tabindex="-1"></a>    simple_counting_scope<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb19-57"><a href="#cb19-57" aria-hidden="true" tabindex="-1"></a>    <span class="op">~</span>simple_counting_scope<span class="op">()</span>;</span>
<span id="cb19-58"><a href="#cb19-58" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-59"><a href="#cb19-59" aria-hidden="true" tabindex="-1"></a>    <span class="co">// simple_counting_scope is immovable and uncopyable</span></span>
<span id="cb19-60"><a href="#cb19-60" aria-hidden="true" tabindex="-1"></a>    simple_counting_scope<span class="op">(</span><span class="kw">const</span> simple_counting_scope<span class="op">&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb19-61"><a href="#cb19-61" aria-hidden="true" tabindex="-1"></a>    simple_counting_scope<span class="op">(</span>simple_counting_scope<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb19-62"><a href="#cb19-62" aria-hidden="true" tabindex="-1"></a>    simple_counting_scope<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span><span class="kw">const</span> simple_counting_scope<span class="op">&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb19-63"><a href="#cb19-63" aria-hidden="true" tabindex="-1"></a>    simple_counting_scope<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span>simple_counting_scope<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb19-64"><a href="#cb19-64" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-65"><a href="#cb19-65" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span>sender S<span class="op">&gt;</span></span>
<span id="cb19-66"><a href="#cb19-66" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> <em>nest-sender</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb19-67"><a href="#cb19-67" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-68"><a href="#cb19-68" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> token <span class="op">{</span></span>
<span id="cb19-69"><a href="#cb19-69" aria-hidden="true" tabindex="-1"></a>      <span class="kw">template</span> <span class="op">&lt;</span>sender S<span class="op">&gt;</span></span>
<span id="cb19-70"><a href="#cb19-70" aria-hidden="true" tabindex="-1"></a>      <em>nest-sender</em><span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>S<span class="op">&gt;&gt;</span> nest<span class="op">(</span>S<span class="op">&amp;&amp;</span> s<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb19-71"><a href="#cb19-71" aria-hidden="true" tabindex="-1"></a>          <span class="kw">noexcept</span><span class="op">(</span>std<span class="op">::</span>is_nothrow_constructible_v<span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>S<span class="op">&gt;</span>, S<span class="op">&gt;)</span>;</span>
<span id="cb19-72"><a href="#cb19-72" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-73"><a href="#cb19-73" aria-hidden="true" tabindex="-1"></a>     <span class="kw">private</span><span class="op">:</span></span>
<span id="cb19-74"><a href="#cb19-74" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> simple_counting_scope;</span>
<span id="cb19-75"><a href="#cb19-75" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-76"><a href="#cb19-76" aria-hidden="true" tabindex="-1"></a>      <span class="kw">explicit</span> token<span class="op">(</span>simple_counting_scope<span class="op">*</span> s<span class="op">)</span> <span class="kw">noexcept</span>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb19-77"><a href="#cb19-77" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-78"><a href="#cb19-78" aria-hidden="true" tabindex="-1"></a>      simple_counting_scope<span class="op">*</span> scope; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb19-79"><a href="#cb19-79" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb19-80"><a href="#cb19-80" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-81"><a href="#cb19-81" aria-hidden="true" tabindex="-1"></a>    token get_token<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb19-82"><a href="#cb19-82" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-83"><a href="#cb19-83" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> close<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb19-84"><a href="#cb19-84" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-85"><a href="#cb19-85" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> <em>join-sender</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb19-86"><a href="#cb19-86" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-87"><a href="#cb19-87" aria-hidden="true" tabindex="-1"></a>    <em>join-sender</em> join<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb19-88"><a href="#cb19-88" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb19-89"><a href="#cb19-89" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-90"><a href="#cb19-90" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> counting_scope <span class="op">{</span></span>
<span id="cb19-91"><a href="#cb19-91" aria-hidden="true" tabindex="-1"></a>    counting_scope<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb19-92"><a href="#cb19-92" aria-hidden="true" tabindex="-1"></a>    <span class="op">~</span>counting_scope<span class="op">()</span>;</span>
<span id="cb19-93"><a href="#cb19-93" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-94"><a href="#cb19-94" aria-hidden="true" tabindex="-1"></a>    <span class="co">// counting_scope is immovable and uncopyable</span></span>
<span id="cb19-95"><a href="#cb19-95" aria-hidden="true" tabindex="-1"></a>    counting_scope<span class="op">(</span><span class="kw">const</span> counting_scope<span class="op">&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb19-96"><a href="#cb19-96" aria-hidden="true" tabindex="-1"></a>    counting_scope<span class="op">(</span>counting_scope<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb19-97"><a href="#cb19-97" aria-hidden="true" tabindex="-1"></a>    counting_scope<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span><span class="kw">const</span> counting_scope<span class="op">&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb19-98"><a href="#cb19-98" aria-hidden="true" tabindex="-1"></a>    counting_scope<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span>counting_scope<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb19-99"><a href="#cb19-99" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-100"><a href="#cb19-100" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span>sender S<span class="op">&gt;</span></span>
<span id="cb19-101"><a href="#cb19-101" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> <em>nest-sender</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb19-102"><a href="#cb19-102" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-103"><a href="#cb19-103" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> token <span class="op">{</span></span>
<span id="cb19-104"><a href="#cb19-104" aria-hidden="true" tabindex="-1"></a>      <span class="kw">template</span> <span class="op">&lt;</span>sender S<span class="op">&gt;</span></span>
<span id="cb19-105"><a href="#cb19-105" aria-hidden="true" tabindex="-1"></a>      <em>nest-sender</em><span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>S<span class="op">&gt;&gt;</span> nest<span class="op">(</span>S<span class="op">&amp;&amp;</span> s<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb19-106"><a href="#cb19-106" aria-hidden="true" tabindex="-1"></a>          <span class="kw">noexcept</span><span class="op">(</span>std<span class="op">::</span>is_nothrow_constructible_v<span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>S<span class="op">&gt;</span>, S<span class="op">&gt;)</span>;</span>
<span id="cb19-107"><a href="#cb19-107" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-108"><a href="#cb19-108" aria-hidden="true" tabindex="-1"></a>     <span class="kw">private</span><span class="op">:</span></span>
<span id="cb19-109"><a href="#cb19-109" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> counting_scope;</span>
<span id="cb19-110"><a href="#cb19-110" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-111"><a href="#cb19-111" aria-hidden="true" tabindex="-1"></a>      <span class="kw">explicit</span> token<span class="op">(</span>counting_scope<span class="op">*</span> s<span class="op">)</span> <span class="kw">noexcept</span>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb19-112"><a href="#cb19-112" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-113"><a href="#cb19-113" aria-hidden="true" tabindex="-1"></a>      counting_scope<span class="op">*</span> scope; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb19-114"><a href="#cb19-114" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb19-115"><a href="#cb19-115" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-116"><a href="#cb19-116" aria-hidden="true" tabindex="-1"></a>    token get_token<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb19-117"><a href="#cb19-117" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-118"><a href="#cb19-118" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> close<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb19-119"><a href="#cb19-119" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-120"><a href="#cb19-120" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> request_stop<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb19-121"><a href="#cb19-121" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-122"><a href="#cb19-122" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> <em>join-sender</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb19-123"><a href="#cb19-123" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-124"><a href="#cb19-124" aria-hidden="true" tabindex="-1"></a>    <em>join-sender</em> join<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb19-125"><a href="#cb19-125" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<h2 data-number="5.2" id="executionasync_scope_token"><span class="header-section-number">5.2</span>
<code class="sourceCode default">execution::async_scope_token</code><a href="#executionasync_scope_token" class="self-link"></a></h2>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Token, <span class="kw">class</span> Sender<span class="op">&gt;</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> async_scope_token <span class="op">=</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>    copyable<span class="op">&lt;</span>Token<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a>    is_nothrow_move_constructible_v<span class="op">&lt;</span>Token<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>    is_nothrow_move_assignable_v<span class="op">&lt;</span>Token<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>    is_nothrow_copy_constructible_v<span class="op">&lt;</span>Token<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a>    is_nothrow_copy_assignable_v<span class="op">&lt;</span>Token<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a>    sender<span class="op">&lt;</span>Sender<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span><span class="op">(</span>Token token, Sender<span class="op">&amp;&amp;</span> snd<span class="op">)</span> <span class="op">{</span></span>
<span id="cb20-10"><a href="#cb20-10" aria-hidden="true" tabindex="-1"></a>      <span class="op">{</span> token<span class="op">.</span>nest<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Sender<span class="op">&gt;(</span>snd<span class="op">))</span> <span class="op">}</span> <span class="op">-&gt;</span> sender;</span>
<span id="cb20-11"><a href="#cb20-11" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span></code></pre></div>
<p>An async scope token is a non-owning handle to an <a href="#executionasync_scope">async scope</a>. The
<code class="sourceCode default">nest()</code> method on a token
attempts to associate its input sender with the handle’s async scope in
a scope-defined way. See <a href="#executionnest"><code class="sourceCode default">execution::nest</code></a>
for the semantics of <code class="sourceCode default">nest()</code>.</p>
<p>An async scope token behaves like a pointer-to-async-scope; tokens
are no-throw copyable and movable, and it is undefined behaviour to
invoke <code class="sourceCode default">nest()</code> on a token that
has outlived its scope.</p>
<h2 data-number="5.3" id="executionnest"><span class="header-section-number">5.3</span>
<code class="sourceCode default">execution::nest</code><a href="#executionnest" class="self-link"></a></h2>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, async_scope_token<span class="op">&lt;</span>Sender<span class="op">&gt;</span> Token<span class="op">&gt;</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> nest<span class="op">(</span>Sender<span class="op">&amp;&amp;</span> snd, Token token<span class="op">)</span> <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span>token<span class="op">.</span>nest<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Sender<span class="op">&gt;(</span>snd<span class="op">))))</span></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span>token<span class="op">.</span>nest<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Sender<span class="op">&gt;(</span>snd<span class="op">)))</span>;</span></code></pre></div>
<p>Attempts to associate the given sender with the given scope token’s
scope in a scope-defined way. When successful, the return value is an
“associated sender” with the same behaviour and possible completions as
the input sender, plus the additional, scope-specific behaviours that
are necessary to implement the scope’s bookkeeping policy. When the
attempt fails, <code class="sourceCode default">nest()</code> must
either eagerly throw an exception, or return a “unassociated sender”
that, when started, unconditionally completes with
<code class="sourceCode default">set_stopped()</code>.</p>
<p>A call to <code class="sourceCode default">nest()</code> does not
start the given sender and is not expected to incur allocations.</p>
<p>When <code class="sourceCode default">nest()</code> returns an
associated sender:</p>
<ul>
<li>connecting and starting the associated sender connects and starts
the given sender; and</li>
<li>the associated sender has exactly the same completions as the input
sender.</li>
</ul>
<p>When <code class="sourceCode default">nest()</code> returns an
unassociated sender:</p>
<ul>
<li>the input sender is discarded and will never be connected or
started; and</li>
<li>the unassociated sender must only complete with
<code class="sourceCode default">set_stopped()</code>.</li>
</ul>
<p>Regardless of whether the returned sender is associated or
unassociated, it is multi-shot if the input sender is multi-shot and
single-shot otherwise.</p>
<h2 data-number="5.4" id="executionspawn"><span class="header-section-number">5.4</span>
<code class="sourceCode default">execution::spawn</code><a href="#executionspawn" class="self-link"></a></h2>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> <span class="op">{</span> <span class="co">// <em>exposition-only</em></span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Env<span class="op">&gt;</span></span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>spawn-env</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Env<span class="op">&gt;</span></span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>spawn-receiver</em> <span class="op">{</span> <span class="co">// <em>exposition-only</em></span></span>
<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> set_value<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> set_stopped<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a>    <em>spawn-env</em><span class="op">&lt;</span>Env<span class="op">&gt;</span> get_env<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb22-12"><a href="#cb22-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb22-13"><a href="#cb22-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-14"><a href="#cb22-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb22-15"><a href="#cb22-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-16"><a href="#cb22-16" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, async_scope_token<span class="op">&lt;</span>Sender<span class="op">&gt;</span> Token, <span class="kw">class</span> Env <span class="op">=</span> empty_env<span class="op">&gt;</span></span>
<span id="cb22-17"><a href="#cb22-17" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> sender_to<span class="op">&lt;</span>Sender, <em>spawn-receiver</em><span class="op">&lt;</span>Env<span class="op">&gt;&gt;</span></span>
<span id="cb22-18"><a href="#cb22-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> spawn<span class="op">(</span>Sender<span class="op">&amp;&amp;</span> snd, Token token, Env env <span class="op">=</span> <span class="op">{})</span>;</span></code></pre></div>
<p>Invokes <code class="sourceCode default">nest(std::forward&lt;Sender&gt;(snd), token)</code>
to associate the given sender with the given token’s scope and then
eagerly starts the resulting sender.</p>
<p>Starting the nested sender involves a dynamic allocation of the
sender’s
<em><code class="sourceCode default">operation-state</code></em>. The
following algorithm determines which <em>Allocator</em> to use for this
allocation:</p>
<ul>
<li>If <code class="sourceCode default">get_allocator(env)</code> is
valid and returns an <em>Allocator</em> then choose that
<em>Allocator</em>.</li>
<li>Otherwise, if
<code class="sourceCode default">get_allocator(get_env(snd))</code> is
valid and returns an <em>Allocator</em> then choose that
<em>Allocator</em>.</li>
<li>Otherwise, choose
<code class="sourceCode default">std::allocator&lt;&gt;</code>.</li>
</ul>
<p>The <em><code class="sourceCode default">operation-state</code></em>
is constructed by connecting the nested sender to a
<em><code class="sourceCode default">spawn-receiver</code></em>. The
<em><code class="sourceCode default">operation-state</code></em> is
destroyed and deallocated after the spawned sender completes.</p>
<p>A <em><code class="sourceCode default">spawn-receiver</code></em>,
<code class="sourceCode default">sr</code>, responds to
<code class="sourceCode default">get_env(sr)</code> with an instance of
a <code class="sourceCode default"><em>spawn-env</em>&lt;Env&gt;</code>,
<code class="sourceCode default">senv</code>. The result of
<code class="sourceCode default">get_allocator(senv)</code> is a copy of
the <em>Allocator</em> used to allocate the
<em><code class="sourceCode default">operation-state</code></em>. For
all other queries, <code class="sourceCode default">Q</code>, the result
of <code class="sourceCode default">Q(senv)</code> is
<code class="sourceCode default">Q(env)</code>.</p>
<p>This is similar to
<code class="sourceCode default">start_detached()</code> from <span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span>, but the scope may observe and
participate in the lifecycle of the work described by the sender. The
<code class="sourceCode default">counting_scope</code> described in this
paper uses this opportunity to keep a count of nested senders that
haven’t finished, and to prevent new work from being started once the
<code class="sourceCode default">counting_scope</code>’s
<em><code class="sourceCode default">join-sender</code></em> has been
started.</p>
<p>The given sender must complete with
<code class="sourceCode default">set_value()</code> or
<code class="sourceCode default">set_stopped()</code> and may not
complete with an error; the user must explicitly handle the errors that
might appear as part of the
<em><code class="sourceCode default">sender-expression</code></em>
passed to <code class="sourceCode default">spawn()</code>.</p>
<p>User expectations will be that
<code class="sourceCode default">spawn()</code> is asynchronous and so,
to uphold the principle of least surprise,
<code class="sourceCode default">spawn()</code> should only be given
non-blocking senders. Using
<code class="sourceCode default">spawn()</code> with a sender generated
by
<code class="sourceCode default">on(sched, <em>blocking-sender</em>)</code>
is a very useful pattern in this context.</p>
<p><em>NOTE:</em> A query for non-blocking start will allow
<code class="sourceCode default">spawn()</code> to be constrained to
require non-blocking start.</p>
<p>Usage example:</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="op">...</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> <span class="dv">100</span>; i<span class="op">++)</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>    spawn<span class="op">(</span>on<span class="op">(</span>sched, some_work<span class="op">(</span>i<span class="op">))</span>, scope<span class="op">.</span>get_token<span class="op">())</span>;</span></code></pre></div>
<h2 data-number="5.5" id="executionspawn_future"><span class="header-section-number">5.5</span>
<code class="sourceCode default">execution::spawn_future</code><a href="#executionspawn_future" class="self-link"></a></h2>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> <span class="op">{</span> <span class="co">// <em>exposition-only</em></span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Env<span class="op">&gt;</span></span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>future-env</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><em>valid-completion-signatures</em> Sigs<span class="op">&gt;</span></span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>future-sender</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, <span class="kw">class</span> Env<span class="op">&gt;</span></span>
<span id="cb24-10"><a href="#cb24-10" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <em>future-sender-t</em> <span class="op">=</span> <span class="co">// <em>exposition-only</em></span></span>
<span id="cb24-11"><a href="#cb24-11" aria-hidden="true" tabindex="-1"></a>    <em>future-sender</em><span class="op">&lt;</span>completion_signatures_of_t<span class="op">&lt;</span>Sender, <em>future-env</em><span class="op">&lt;</span>Env<span class="op">&gt;&gt;&gt;</span>;</span>
<span id="cb24-12"><a href="#cb24-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-13"><a href="#cb24-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb24-14"><a href="#cb24-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-15"><a href="#cb24-15" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, async_scope_token<span class="op">&lt;</span>Sender<span class="op">&gt;</span> Token, <span class="kw">class</span> Env <span class="op">=</span> empty_env<span class="op">&gt;</span></span>
<span id="cb24-16"><a href="#cb24-16" aria-hidden="true" tabindex="-1"></a><em>future-sender-t</em><span class="op">&lt;</span>Sender, Env<span class="op">&gt;</span> spawn_future<span class="op">(</span>Sender<span class="op">&amp;&amp;</span> snd, Token token, Env env <span class="op">=</span> <span class="op">{})</span>;</span></code></pre></div>
<p>Invokes <code class="sourceCode default">nest(std::forward&lt;Sender&gt;(snd), token)</code>
to associate the given sender with the given token’s scope, eagerly
starts the resulting sender, and returns a
<em><code class="sourceCode default">future-sender</code></em> that
provides access to the result of the given sender.</p>
<p>Similar to <code class="sourceCode default">spawn()</code>, starting
the nested sender involves a dynamic allocation of some state.
<code class="sourceCode default">spawn_future()</code> chooses an
<em>Allocator</em> for this allocation in the same way
<code class="sourceCode default">spawn()</code> does: use the result of
<code class="sourceCode default">get_allocator(env)</code> if that is a
valid expression, otherwise use the result of
<code class="sourceCode default">get_allocator(get_env(snd))</code> if
that is a valid expression, otherwise use a
<code class="sourceCode default">std::allocator&lt;&gt;</code>.</p>
<p>Unlike <code class="sourceCode default">spawn()</code>, the
dynamically allocated state contains more than just an
<em><code class="sourceCode default">operation-state</code></em> for the
nested sender; the state must also contain storage for the result of the
nested sender, however it eventually completes, and synchronization
facilities for resolving the race between the nested sender’s production
of its result and the returned sender’s consumption or abandonment of
that result.</p>
<p>Also unlike <code class="sourceCode default">spawn()</code>,
<code class="sourceCode default">spawn_future()</code> returns a
<em><code class="sourceCode default">future-sender</code></em> rather
than <code class="sourceCode default">void</code>. The returned sender,
<code class="sourceCode default">fs</code>, is a handle to the spawned
work that can be used to consume or abandon the result of that work.
When <code class="sourceCode default">fs</code> is connected and
started, it waits for the spawned sender to complete and then completes
itself with the spawned sender’s result. If
<code class="sourceCode default">fs</code> is destroyed before being
connected, or if <code class="sourceCode default">fs</code> <em>is</em>
connected but then the resulting
<em><code class="sourceCode default">operation-state</code></em> is
destroyed before being started, then a stop request is sent to the
spawned sender in an effort to short-circuit the computation of a result
that will not be observed. If <code class="sourceCode default">fs</code>
receives a stop request from its receiver before the spawned sender
completes, the stop request is forwarded to the spawned sender and then
<code class="sourceCode default">fs</code> completes; if the spawned
sender happens to complete between
<code class="sourceCode default">fs</code> forwarding the stop request
and completing itself then <code class="sourceCode default">fs</code>
may complete with the result of the spawned sender as if the stop
request was never received but, otherwise,
<code class="sourceCode default">fs</code> completes with
<code class="sourceCode default">stopped</code> and the result of the
spawned sender is ignored. The completion signatures of
<code class="sourceCode default">fs</code> include
<code class="sourceCode default">set_stopped()</code> and all the
completion signatures of the spawned sender.</p>
<p>The receiver, <code class="sourceCode default">fr</code>, that is
connected to the nested sender responds to
<code class="sourceCode default">get_env(fr)</code> with an instance of
<code class="sourceCode default"><em>future-env</em>&lt;Env&gt;</code>,
<code class="sourceCode default">fenv</code>. The result of
<code class="sourceCode default">get_allocator(fenv)</code> is a copy of
the <em>Allocator</em> used to allocate the dynamically allocated state.
The result of
<code class="sourceCode default">get_stop_token(fenv)</code> is a stop
token that will be “triggered” (i.e. signal that stop is requested)
when:</p>
<ul>
<li>the returned
<em><code class="sourceCode default">future-sender</code></em> is
dropped;</li>
<li>the returned
<em><code class="sourceCode default">future-sender</code></em> receives
a stop request; or</li>
<li>the stop token returned from
<code class="sourceCode default">get_stop_token(env)</code> is triggered
if <code class="sourceCode default">get_stop_token(env)</code> is a
valid expression.</li>
</ul>
<p>For all other queries, <code class="sourceCode default">Q</code>, the
result of <code class="sourceCode default">Q(fenv)</code> is
<code class="sourceCode default">Q(env)</code>.</p>
<p>This is similar to
<code class="sourceCode default">ensure_started()</code> from <span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span>, but the scope may observe and
participate in the lifecycle of the work described by the sender. The
<code class="sourceCode default">counting_scope</code> described in this
paper uses this opportunity to keep a count of nested senders that
haven’t finished, and to prevent new work from being started once the
<code class="sourceCode default">counting_scope</code>’s
<em><code class="sourceCode default">join-sender</code></em> has been
started.</p>
<p>Unlike <code class="sourceCode default">spawn()</code>, the sender
given to <code class="sourceCode default">spawn_future()</code> is not
constrained on a given shape. It may send different types of values, and
it can complete with errors.</p>
<p><em>NOTE:</em> there is a race between the completion of the given
sender and the start of the returned sender. The spawned sender and the
returned <em><code class="sourceCode default">future-sender</code></em>
use the synchronization facilities in the dynamically allocated state to
resolve this race.</p>
<p>Cancelling the returned sender requests cancellation of the given
sender, <code class="sourceCode default">snd</code>, but does not affect
any other senders.</p>
<p>Usage example:</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="op">...</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a>sender <span class="kw">auto</span> snd <span class="op">=</span> spawn_future<span class="op">(</span>on<span class="op">(</span>sched, key_work<span class="op">())</span>, scope<span class="op">)</span> <span class="op">|</span> then<span class="op">(</span>continue_fun<span class="op">)</span>;</span>
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> <span class="dv">10</span>; i<span class="op">++)</span></span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a>    spawn<span class="op">(</span>on<span class="op">(</span>sched, other_work<span class="op">(</span>i<span class="op">))</span>, scope<span class="op">)</span>;</span>
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> when_all<span class="op">(</span>scope<span class="op">.</span>join<span class="op">()</span>, std<span class="op">::</span>move<span class="op">(</span>snd<span class="op">))</span>;</span></code></pre></div>
<h2 data-number="5.6" id="executionsimple_counting_scope"><span class="header-section-number">5.6</span>
<code class="sourceCode default">execution::simple_counting_scope</code><a href="#executionsimple_counting_scope" class="self-link"></a></h2>
<div class="sourceCode" id="cb26"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> simple_counting_scope <span class="op">{</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a>    simple_counting_scope<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">~</span>simple_counting_scope<span class="op">()</span>;</span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">// simple_counting_scope is immovable and uncopyable</span></span>
<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a>    simple_counting_scope<span class="op">(</span><span class="kw">const</span> simple_counting_scope<span class="op">&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a>    simple_counting_scope<span class="op">(</span>simple_counting_scope<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a>    simple_counting_scope<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span><span class="kw">const</span> simple_counting_scope<span class="op">&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a>    simple_counting_scope<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span>simple_counting_scope<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span>sender S<span class="op">&gt;</span></span>
<span id="cb26-12"><a href="#cb26-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> <em>nest-sender</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb26-13"><a href="#cb26-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-14"><a href="#cb26-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> token <span class="op">{</span></span>
<span id="cb26-15"><a href="#cb26-15" aria-hidden="true" tabindex="-1"></a>      <span class="kw">template</span> <span class="op">&lt;</span>sender S<span class="op">&gt;</span></span>
<span id="cb26-16"><a href="#cb26-16" aria-hidden="true" tabindex="-1"></a>      <em>nest-sender</em><span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>S<span class="op">&gt;&gt;</span> nest<span class="op">(</span>S<span class="op">&amp;&amp;</span> s<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb26-17"><a href="#cb26-17" aria-hidden="true" tabindex="-1"></a>          <span class="kw">noexcept</span><span class="op">(</span>std<span class="op">::</span>is_nothrow_constructible_v<span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>S<span class="op">&gt;</span>, S<span class="op">&gt;)</span>;</span>
<span id="cb26-18"><a href="#cb26-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-19"><a href="#cb26-19" aria-hidden="true" tabindex="-1"></a>     <span class="kw">private</span><span class="op">:</span></span>
<span id="cb26-20"><a href="#cb26-20" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> simple_counting_scope;</span>
<span id="cb26-21"><a href="#cb26-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-22"><a href="#cb26-22" aria-hidden="true" tabindex="-1"></a>      <span class="kw">explicit</span> token<span class="op">(</span>simple_counting_scope<span class="op">*</span> s<span class="op">)</span> <span class="kw">noexcept</span>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb26-23"><a href="#cb26-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-24"><a href="#cb26-24" aria-hidden="true" tabindex="-1"></a>      simple_counting_scope<span class="op">*</span> scope; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb26-25"><a href="#cb26-25" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb26-26"><a href="#cb26-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-27"><a href="#cb26-27" aria-hidden="true" tabindex="-1"></a>    token get_token<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-28"><a href="#cb26-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-29"><a href="#cb26-29" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> close<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-30"><a href="#cb26-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-31"><a href="#cb26-31" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> <em>join-sender</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb26-32"><a href="#cb26-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-33"><a href="#cb26-33" aria-hidden="true" tabindex="-1"></a>    <em>join-sender</em> join<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-34"><a href="#cb26-34" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>A <code class="sourceCode default">simple_counting_scope</code>
maintains a count of outstanding operations and goes through several
states durings its lifetime:</p>
<ul>
<li>unused</li>
<li>open</li>
<li>closed</li>
<li>open-and-joining</li>
<li>closed-and-joining</li>
<li>unused-and-closed</li>
<li>joined</li>
</ul>
<p>The following diagram illustrates the
<code class="sourceCode default">simple_counting_scope</code>’s state
machine:</p>
<p><img src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXMtYXNjaWkiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBjb250ZW50U3R5bGVUeXBlPSJ0ZXh0L2NzcyIgaGVpZ2h0PSI5MzhweCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSIgc3R5bGU9IndpZHRoOjc5OHB4O2hlaWdodDo5MzhweDtiYWNrZ3JvdW5kOiNGRkZGRkY7IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA3OTggOTM4IiB3aWR0aD0iNzk4cHgiIHpvb21BbmRQYW49Im1hZ25pZnkiPjxkZWZzLz48Zz48ZyBpZD0idW51c2VkIj48cmVjdCBmaWxsPSIjRjFGMUYxIiBoZWlnaHQ9Ijc4Ljg4NjciIHJ4PSIxMi41IiByeT0iMTIuNSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7IiB3aWR0aD0iMTI3IiB4PSIzMDEuNTgiIHk9Ijg2Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7IiB4MT0iMzAxLjU4IiB4Mj0iNDI4LjU4IiB5MT0iMTEyLjQ4ODMiIHkyPSIxMTIuNDg4MyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjE0IiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjUxIiB4PSIzMzkuNTgiIHk9IjEwNC41MzUyIj51bnVzZWQ8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNTciIHg9IjMwNi41OCIgeT0iMTI5LjA4OTgiPmNvdW50ID0gMDwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIxMDciIHg9IjMwNi41OCIgeT0iMTQzLjIyMjciPm5lc3QoKSBjYW4gc3VjY2VlZDwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI5OSIgeD0iMzA2LjU4IiB5PSIxNTcuMzU1NSI+am9pbigpIG5vdCBuZWVkZWQ8L3RleHQ+PC9nPjxnIGlkPSJvcGVuIj48cmVjdCBmaWxsPSIjRjFGMUYxIiBoZWlnaHQ9Ijc4Ljg4NjciIHJ4PSIxMi41IiByeT0iMTIuNSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7IiB3aWR0aD0iMTI3IiB4PSIxOTYuNTgiIHk9IjI0MS44OCIvPjxsaW5lIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgeDE9IjE5Ni41OCIgeDI9IjMyMy41OCIgeTE9IjI2OC4zNjgzIiB5Mj0iMjY4LjM2ODMiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIzNSIgeD0iMjQyLjU4IiB5PSIyNjAuNDE1MiI+b3BlbjwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI1NyIgeD0iMjAxLjU4IiB5PSIyODQuOTY5OCI+Y291bnQgJiM4ODA1OyAwPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjEwNyIgeD0iMjAxLjU4IiB5PSIyOTkuMTAyNyI+bmVzdCgpIGNhbiBzdWNjZWVkPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9Ijc3IiB4PSIyMDEuNTgiIHk9IjMxMy4yMzU1Ij5qb2luKCkgbmVlZGVkPC90ZXh0PjwvZz48ZyBpZD0iY2xvc2VkIj48cmVjdCBmaWxsPSIjRjFGMUYxIiBoZWlnaHQ9Ijc4Ljg4NjciIHJ4PSIxMi41IiByeT0iMTIuNSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7IiB3aWR0aD0iOTciIHg9IjE5Mi41OCIgeT0iNDEyLjc3Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7IiB4MT0iMTkyLjU4IiB4Mj0iMjg5LjU4IiB5MT0iNDM5LjI1ODMiIHkyPSI0MzkuMjU4MyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjE0IiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjQ0IiB4PSIyMTkuMDgiIHk9IjQzMS4zMDUyIj5jbG9zZWQ8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNTciIHg9IjE5Ny41OCIgeT0iNDU1Ljg1OTgiPmNvdW50ICYjODgwNTsgMDwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI1OSIgeD0iMTk3LjU4IiB5PSI0NjkuOTkyNyI+bmVzdCgpIGZhaWxzPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9Ijc3IiB4PSIxOTcuNTgiIHk9IjQ4NC4xMjU1Ij5qb2luKCkgbmVlZGVkPC90ZXh0PjwvZz48ZyBpZD0ib3Blbl9hbmRfam9pbmluZyI+PHJlY3QgZmlsbD0iI0YxRjFGMSIgaGVpZ2h0PSI3OC44ODY3IiByeD0iMTIuNSIgcnk9IjEyLjUiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgd2lkdGg9IjE0NSIgeD0iMTIuNTgiIHk9IjQxMi43NyIvPjxsaW5lIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgeDE9IjEyLjU4IiB4Mj0iMTU3LjU4IiB5MT0iNDM5LjI1ODMiIHkyPSI0MzkuMjU4MyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjE0IiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjEyNSIgeD0iMjIuNTgiIHk9IjQzMS4zMDUyIj5vcGVuLWFuZC1qb2luaW5nPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjU3IiB4PSIxNy41OCIgeT0iNDU1Ljg1OTgiPmNvdW50ICYjODgwNTsgMDwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIxMDciIHg9IjE3LjU4IiB5PSI0NjkuOTkyNyI+bmVzdCgpIGNhbiBzdWNjZWVkPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9Ijc2IiB4PSIxNy41OCIgeT0iNDg0LjEyNTUiPmpvaW4oKSBydW5uaW5nPC90ZXh0PjwvZz48ZyBpZD0iY2xvc2VkX2FuZF9qb2luaW5nIj48cmVjdCBmaWxsPSIjRjFGMUYxIiBoZWlnaHQ9Ijc4Ljg4NjciIHJ4PSIxMi41IiByeT0iMTIuNSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7IiB3aWR0aD0iMTU0IiB4PSIxOTkuMDgiIHk9IjU4My42NiIvPjxsaW5lIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgeDE9IjE5OS4wOCIgeDI9IjM1My4wOCIgeTE9IjYxMC4xNDgzIiB5Mj0iNjEwLjE0ODMiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIxMzQiIHg9IjIwOS4wOCIgeT0iNjAyLjE5NTIiPmNsb3NlZC1hbmQtam9pbmluZzwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI1NyIgeD0iMjA0LjA4IiB5PSI2MjYuNzQ5OCI+Y291bnQgJiM4ODA1OyAwPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjU5IiB4PSIyMDQuMDgiIHk9IjY0MC44ODI3Ij5uZXN0KCkgZmFpbHM8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNzYiIHg9IjIwNC4wOCIgeT0iNjU1LjAxNTUiPmpvaW4oKSBydW5uaW5nPC90ZXh0PjwvZz48ZyBpZD0idW51c2VkX2FuZF9jbG9zZWQiPjxyZWN0IGZpbGw9IiNGMUYxRjEiIGhlaWdodD0iNzguODg2NyIgcng9IjEyLjUiIHJ5PSIxMi41IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiIHdpZHRoPSIxNTciIHg9IjMyNC41OCIgeT0iNDEyLjc3Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7IiB4MT0iMzI0LjU4IiB4Mj0iNDgxLjU4IiB5MT0iNDM5LjI1ODMiIHkyPSI0MzkuMjU4MyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjE0IiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjEzNyIgeD0iMzM0LjU4IiB5PSI0MzEuMzA1MiI+dW51c2VkLWFuZC1jbG9zZWQ8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNTciIHg9IjMyOS41OCIgeT0iNDU1Ljg1OTgiPmNvdW50ID0gMDwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI1OSIgeD0iMzI5LjU4IiB5PSI0NjkuOTkyNyI+bmVzdCgpIGZhaWxzPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9Ijk5IiB4PSIzMjkuNTgiIHk9IjQ4NC4xMjU1Ij5qb2luKCkgbm90IG5lZWRlZDwvdGV4dD48L2c+PGcgaWQ9ImpvaW5lZCI+PHJlY3QgZmlsbD0iI0YxRjFGMSIgaGVpZ2h0PSI3OC44ODY3IiByeD0iMTIuNSIgcnk9IjEyLjUiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgd2lkdGg9IjExOSIgeD0iMTg0LjU4IiB5PSI3NTQuNTQiLz48bGluZSBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiIHgxPSIxODQuNTgiIHgyPSIzMDMuNTgiIHkxPSI3ODEuMDI4MyIgeTI9Ijc4MS4wMjgzIi8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTQiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNDMiIHg9IjIyMi41OCIgeT0iNzczLjA3NTIiPmpvaW5lZDwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI1NyIgeD0iMTg5LjU4IiB5PSI3OTcuNjI5OCI+Y291bnQgPSAwPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjU5IiB4PSIxODkuNTgiIHk9IjgxMS43NjI3Ij5uZXN0KCkgZmFpbHM8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iOTkiIHg9IjE4OS41OCIgeT0iODI1Ljg5NTUiPmpvaW4oKSBub3QgbmVlZGVkPC90ZXh0PjwvZz48ZWxsaXBzZSBjeD0iMzY1LjA4IiBjeT0iMTYiIGZpbGw9IiMyMjIyMjIiIHJ4PSIxMCIgcnk9IjEwIiBzdHlsZT0ic3Ryb2tlOiMyMjIyMjI7c3Ryb2tlLXdpZHRoOjEuMDsiLz48ZWxsaXBzZSBjeD0iNDM0LjA4IiBjeT0iOTIxLjQzIiBmaWxsPSJub25lIiByeD0iMTEiIHJ5PSIxMSIgc3R5bGU9InN0cm9rZTojMjIyMjIyO3N0cm9rZS13aWR0aDoxLjA7Ii8+PGVsbGlwc2UgY3g9IjQzNC4wOCIgY3k9IjkyMS40MyIgZmlsbD0iIzIyMjIyMiIgcng9IjYiIHJ5PSI2IiBzdHlsZT0ic3Ryb2tlOiMyMjIyMjI7c3Ryb2tlLXdpZHRoOjEuMDsiLz48IS0tbGluayAqc3RhcnQqIHRvIHVudXNlZC0tPjxnIGlkPSJsaW5rXypzdGFydCpfdW51c2VkIj48cGF0aCBkPSJNMzY1LjA4LDI2LjE2IEMzNjUuMDgsMzkuMjUgMzY1LjA4LDU4LjEgMzY1LjA4LDc5LjU0ICIgZmlsbD0ibm9uZSIgaWQ9IipzdGFydCotdG8tdW51c2VkIiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48cG9seWdvbiBmaWxsPSIjMTgxODE4IiBwb2ludHM9IjM2NS4wOCw4NS41NCwzNjkuMDgsNzYuNTQsMzY1LjA4LDgwLjU0LDM2MS4wOCw3Ni41NCwzNjUuMDgsODUuNTQiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIvPjwvZz48IS0tbGluayB1bnVzZWQgdG8gb3Blbi0tPjxnIGlkPSJsaW5rX3VudXNlZF9vcGVuIj48cGF0aCBkPSJNMzM4LjU4LDE2NS4yNyBDMzIyLjY3LDE4OC42IDMwNS44NjA1LDIxMy4yMjMgMjg5Ljk1MDUsMjM2LjU1MyAiIGZpbGw9Im5vbmUiIGlkPSJ1bnVzZWQtdG8tb3BlbiIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIyODYuNTcsMjQxLjUxLDI5NC45NDU0LDIzNi4zMjgxLDI4OS4zODcxLDIzNy4zNzkxLDI4OC4zMzYsMjMxLjgyMDgsMjg2LjU3LDI0MS41MSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMzUiIHg9IjMxNy4wOCIgeT0iMjA4LjQ0ODQiPm5lc3QoKTwvdGV4dD48L2c+PCEtLWxpbmsgdW51c2VkIHRvIHVudXNlZF9hbmRfY2xvc2VkLS0+PGcgaWQ9ImxpbmtfdW51c2VkX3VudXNlZF9hbmRfY2xvc2VkIj48cGF0aCBkPSJNMzY5LjYzLDE2NS4yOSBDMzc2LjkzLDIyNy43NiAzOTAuNTIzLDM0My44NjA2IDM5Ny44MzMsNDA2LjM2MDYgIiBmaWxsPSJub25lIiBpZD0idW51c2VkLXRvLXVudXNlZF9hbmRfY2xvc2VkIiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48cG9seWdvbiBmaWxsPSIjMTgxODE4IiBwb2ludHM9IjM5OC41Myw0MTIuMzIsNDAxLjQ1NzQsNDAyLjkxNjMsMzk3Ljk0OTIsNDA3LjM1MzksMzkzLjUxMTYsNDAzLjg0NTYsMzk4LjUzLDQxMi4zMiIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNDEiIHg9IjM4OC4wOCIgeT0iMjg2LjM5ODQiPmNsb3NlKCk8L3RleHQ+PC9nPjwhLS1saW5rIHVudXNlZCB0byBvcGVuX2FuZF9qb2luaW5nLS0+PGcgaWQ9ImxpbmtfdW51c2VkX29wZW5fYW5kX2pvaW5pbmciPjxwYXRoIGQ9Ik0zMDEuMTIsMTM1Ljc5IEMyMzkuNTUsMTQ4LjQ1IDE0OS4xOSwxNzcuMzkgMTAzLjA4LDI0MS44OCBDNjcuMjIsMjkyLjAzIDY5Ljk5MjQsMzYxLjI1MzEgNzYuNjEyNCw0MDYuNTUzMSAiIGZpbGw9Im5vbmUiIGlkPSJ1bnVzZWQtdG8tb3Blbl9hbmRfam9pbmluZyIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSI3Ny40OCw0MTIuNDksODAuMTM2Niw0MDMuMDA2Miw3Ni43NTcsNDA3LjU0MjUsNzIuMjIwNiw0MDQuMTYzLDc3LjQ4LDQxMi40OSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNzQiIHg9IjEwNC4wOCIgeT0iMjc4Ljg5ODQiPmpvaW4tc2VuZGVyPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjQ0IiB4PSIxMTkuMDgiIHk9IjI5NC4yMDg5Ij5zdGFydGVkPC90ZXh0PjwvZz48IS0tbGluayBvcGVuIHRvIGNsb3NlZC0tPjxnIGlkPSJsaW5rX29wZW5fY2xvc2VkIj48cGF0aCBkPSJNMjU1LjcyLDMyMS4wNyBDMjUyLjY0LDM0OC40NCAyNDkuMjAwNSwzNzkuMDA3NiAyNDYuMTIwNSw0MDYuMzk3NiAiIGZpbGw9Im5vbmUiIGlkPSJvcGVuLXRvLWNsb3NlZCIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIyNDUuNDUsNDEyLjM2LDI1MC40MzA3LDQwMy44NjM0LDI0Ni4wMDg3LDQwNy4zOTEzLDI0Mi40ODA4LDQwMi45Njk0LDI0NS40NSw0MTIuMzYiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjQxIiB4PSIyNTQuMDgiIHk9IjM3MS44Mzg0Ij5jbG9zZSgpPC90ZXh0PjwvZz48IS0tbGluayBvcGVuIHRvIG9wZW5fYW5kX2pvaW5pbmctLT48ZyBpZD0ibGlua19vcGVuX29wZW5fYW5kX2pvaW5pbmciPjxwYXRoIGQ9Ik0yMDAuODIsMzIxLjE4IEMxODguNSwzMzAuMyAxNzUuOTcsMzQwLjM5IDE2NS4wOCwzNTAuNzcgQzE0NS41NSwzNjkuMzggMTMwLjE4OTUsMzg4LjAyNDcgMTE1LjY0OTUsNDA3LjU4NDcgIiBmaWxsPSJub25lIiBpZD0ib3Blbi10by1vcGVuX2FuZF9qb2luaW5nIiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48cG9seWdvbiBmaWxsPSIjMTgxODE4IiBwb2ludHM9IjExMi4wNyw0MTIuNCwxMjAuNjQ5NCw0MDcuNTYzMywxMTUuMDUyOSw0MDguMzg3MiwxMTQuMjI5LDQwMi43OTA3LDExMi4wNyw0MTIuNCIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNzQiIHg9IjE2Ni4wOCIgeT0iMzY0LjMzODQiPmpvaW4tc2VuZGVyPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjQ0IiB4PSIxODEuMDgiIHk9IjM3OS42NDg5Ij5zdGFydGVkPC90ZXh0PjwvZz48IS0tbGluayBjbG9zZWQgdG8gY2xvc2VkX2FuZF9qb2luaW5nLS0+PGcgaWQ9ImxpbmtfY2xvc2VkX2Nsb3NlZF9hbmRfam9pbmluZyI+PHBhdGggZD0iTTIyMC42MSw0OTIuMDEgQzIxMy4zNCw1MTAuOTIgMjA4LjYxLDUzMy44MSAyMTYuMDgsNTUzLjY2IEMyMjAuMDksNTY0LjMxIDIyMi44MTQ3LDU2OS43MTY3IDIzMC4wODQ3LDU3OC42OTY3ICIgZmlsbD0ibm9uZSIgaWQ9ImNsb3NlZC10by1jbG9zZWRfYW5kX2pvaW5pbmciIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iMjMzLjg2LDU4My4zNiwyMzEuMzA1OSw1NzMuODQ4MSwyMzAuNzEzOSw1NzkuNDczOSwyMjUuMDg4MSw1NzguODgxOSwyMzMuODYsNTgzLjM2IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI3NCIgeD0iMjE3LjA4IiB5PSI1MzUuMjI4NCI+am9pbi1zZW5kZXI8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNDQiIHg9IjIzMi4wOCIgeT0iNTUwLjUzODkiPnN0YXJ0ZWQ8L3RleHQ+PC9nPjwhLS1saW5rIG9wZW5fYW5kX2pvaW5pbmcgdG8gY2xvc2VkX2FuZF9qb2luaW5nLS0+PGcgaWQ9Imxpbmtfb3Blbl9hbmRfam9pbmluZ19jbG9zZWRfYW5kX2pvaW5pbmciPjxwYXRoIGQ9Ik0xMDkuNTEsNDkxLjggQzEyMy4zNSw1MTEuNzcgMTQxLjkyLDUzNS42NiAxNjIuMDgsNTUzLjY2IEMxNzQuMTQsNTY0LjQyIDE4My4wNTA5LDU3MS4yIDE5Ny4wMTA5LDU4MC4wNCAiIGZpbGw9Im5vbmUiIGlkPSJvcGVuX2FuZF9qb2luaW5nLXRvLWNsb3NlZF9hbmRfam9pbmluZyIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIyMDIuMDgsNTgzLjI1LDE5Ni42MTYzLDU3NS4wNTU2LDE5Ny44NTU3LDU4MC41NzUsMTkyLjMzNjMsNTgxLjgxNDUsMjAyLjA4LDU4My4yNSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNDEiIHg9IjE2My4wOCIgeT0iNTQyLjcyODQiPmNsb3NlKCk8L3RleHQ+PC9nPjwhLS1saW5rIHVudXNlZF9hbmRfY2xvc2VkIHRvIGNsb3NlZF9hbmRfam9pbmluZy0tPjxnIGlkPSJsaW5rX3VudXNlZF9hbmRfY2xvc2VkX2Nsb3NlZF9hbmRfam9pbmluZyI+PHBhdGggZD0iTTM1OC45MSw0OTEuODUgQzM0OS41LDUwMS4xMyAzNDAuMDIsNTExLjM1IDMzMi4wOCw1MjEuNjYgQzMxNy40Niw1NDAuNjQgMzA2Ljk4NzIsNTU4LjU2MDggMjk3LjA2NzIsNTc3LjkxMDggIiBmaWxsPSJub25lIiBpZD0idW51c2VkX2FuZF9jbG9zZWQtdG8tY2xvc2VkX2FuZF9qb2luaW5nIiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48cG9seWdvbiBmaWxsPSIjMTgxODE4IiBwb2ludHM9IjI5NC4zMyw1ODMuMjUsMzAxLjk5NTMsNTc3LjA2NTksMjk2LjYxMSw1NzguODAwNiwyOTQuODc2Myw1NzMuNDE2MywyOTQuMzMsNTgzLjI1IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI3NCIgeD0iMzMzLjA4IiB5PSI1MzUuMjI4NCI+am9pbi1zZW5kZXI8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNDQiIHg9IjM0OC4wOCIgeT0iNTUwLjUzODkiPnN0YXJ0ZWQ8L3RleHQ+PC9nPjwhLS1saW5rIGNsb3NlZF9hbmRfam9pbmluZyB0byBqb2luZWQtLT48ZyBpZD0ibGlua19jbG9zZWRfYW5kX2pvaW5pbmdfam9pbmVkIj48cGF0aCBkPSJNMjU1Ljg5LDY2My4wMiBDMjUxLjg5LDY3Mi40NSAyNDguMjUsNjgyLjY2IDI0Ni4wOCw2OTIuNTQgQzI0MS42Niw3MTIuNjQgMjQwLjc0NjksNzI5LjU1MTcgMjQxLjE5NjksNzQ4LjQxMTcgIiBmaWxsPSJub25lIiBpZD0iY2xvc2VkX2FuZF9qb2luaW5nLXRvLWpvaW5lZCIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIyNDEuMzQsNzU0LjQxLDI0NS4xMjQyLDc0NS4zMTcxLDI0MS4yMjA3LDc0OS40MTE0LDIzNy4xMjY1LDc0NS41MDgsMjQxLjM0LDc1NC40MSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTAwIiB4PSIyNjguNTgiIHk9IjcwNi4xMDg0Ij5jb3VudCByZWFjaGVzIDA8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTQzIiB4PSIyNDcuMDgiIHk9IjcyMS40MTg5Ij5qb2luLXNlbmRlciBjb21wbGV0ZXM8L3RleHQ+PC9nPjwhLS1saW5rIG9wZW5fYW5kX2pvaW5pbmcgdG8gam9pbmVkLS0+PGcgaWQ9Imxpbmtfb3Blbl9hbmRfam9pbmluZ19qb2luZWQiPjxwYXRoIGQ9Ik02MC4yNyw0OTIuMTQgQzM1Ljc3LDUzNS45NyA2LDYwOC4xNyAzNi4wOCw2NjIuNTQgQzY3LjQ0LDcxOS4yNCAxMjkuMzAwNiw3NTIuNDA4NSAxNzguOTMwNiw3NzEuNzc4NSAiIGZpbGw9Im5vbmUiIGlkPSJvcGVuX2FuZF9qb2luaW5nLXRvLWpvaW5lZCIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIxODQuNTIsNzczLjk2LDE3Ny41OTAyLDc2Ni45NjE1LDE3OS44NjIyLDc3Mi4xNDIxLDE3NC42ODE2LDc3NC40MTQxLDE4NC41Miw3NzMuOTYiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjEwMCIgeD0iNTguNTgiIHk9IjYyMC42Njg0Ij5jb3VudCByZWFjaGVzIDA8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTQzIiB4PSIzNy4wOCIgeT0iNjM1Ljk3ODkiPmpvaW4tc2VuZGVyIGNvbXBsZXRlczwvdGV4dD48L2c+PCEtLWxpbmsgam9pbmVkIHRvICplbmQqLS0+PGcgaWQ9Imxpbmtfam9pbmVkXyplbmQqIj48cGF0aCBkPSJNMjMyLjI3LDgzMy44NyBDMjI5Ljg2LDg0OS44OSAyMzAuNjgsODY3LjY1IDI0MS4wOCw4ODAuNDMgQzI2NC4zNiw5MDkuMDMgMzc5LjIxOSw5MTcuNDkwNiA0MTYuODY5LDkxOS41NjA2ICIgZmlsbD0ibm9uZSIgaWQ9ImpvaW5lZC10by0qZW5kKiIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSI0MjIuODYsOTE5Ljg5LDQxNC4wOTMyLDkxNS40MDIsNDE3Ljg2NzUsOTE5LjYxNTUsNDEzLjY1NCw5MjMuMzg5OSw0MjIuODYsOTE5Ljg5IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIxNjUiIHg9IjI0Mi4wOCIgeT0iODc2Ljk5ODQiPn5zaW1wbGVfY291bnRpbmdfc2NvcGUoKTwvdGV4dD48L2c+PCEtLWxpbmsgdW51c2VkX2FuZF9jbG9zZWQgdG8gKmVuZCotLT48ZyBpZD0ibGlua191bnVzZWRfYW5kX2Nsb3NlZF8qZW5kKiI+PHBhdGggZD0iTTQwOC42OCw0OTEuODkgQzQwOS45NSw1MDEuNTkgNDExLjE4LDUxMS45OSA0MTIuMDgsNTIxLjY2IEM0MjYuNDMsNjc1LjYxIDQzMi4yOTc5LDg1Ny45NDI1IDQzMy42MTc5LDkwMy45MzI1ICIgZmlsbD0ibm9uZSIgaWQ9InVudXNlZF9hbmRfY2xvc2VkLXRvLSplbmQqIiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48cG9seWdvbiBmaWxsPSIjMTgxODE4IiBwb2ludHM9IjQzMy43OSw5MDkuOTMsNDM3LjUzMDEsOTAwLjgxODksNDMzLjY0NjUsOTA0LjkzMjEsNDI5LjUzMzQsOTAxLjA0ODUsNDMzLjc5LDkwOS45MyIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTY1IiB4PSI0MjcuMDgiIHk9IjcxMy42MDg0Ij5+c2ltcGxlX2NvdW50aW5nX3Njb3BlKCk8L3RleHQ+PC9nPjwhLS1saW5rIHVudXNlZCB0byAqZW5kKi0tPjxnIGlkPSJsaW5rX3VudXNlZF8qZW5kKiI+PHBhdGggZD0iTTQyOC43NywxMzUuODggQzUwNS40NiwxNTEuMjYgNjI0LjA4LDE4OS43MSA2MjQuMDgsMjgwLjMzIEM2MjQuMDgsMjgwLjMzIDYyNC4wOCwyODAuMzMgNjI0LjA4LDc5NC45OSBDNjI0LjA4LDg4MS4zNSA0OTEuNTgxOCw5MTAuNjQ1MSA0NTEuMDMxOCw5MTcuNjc1MSAiIGZpbGw9Im5vbmUiIGlkPSJ1bnVzZWQtdG8tKmVuZCoiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iNDQ1LjEyLDkxOC43LDQ1NC42NzEsOTIxLjEwMzgsNDUwLjA0NjUsOTE3Ljg0NTksNDUzLjMwNDUsOTEzLjIyMTQsNDQ1LjEyLDkxOC43IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIxNjUiIHg9IjYyNS4wOCIgeT0iNTQyLjcyODQiPn5zaW1wbGVfY291bnRpbmdfc2NvcGUoKTwvdGV4dD48L2c+PCEtLVNSQz1bYlA5REppR20zOE50RktLcUFxMmdERWtIdTI4S0xMNWdlQVl1ZXBmVDhUWHBhQmRPZDhKeWs2dElmQVlwY3RkRnh4REpjeEpLODRPUzJIaG5MTm1OdjhKLTMxWnlMTHFWLW1UUks0ZmlvZS0gLW5IUlYzYUFJSXpMNmg1YUMwbndISEJveTVWOXBrUDBsVDFjbGthbW9jOE1tS0YyaEphQnI4c2huQTh3Qlg0M3d4YnVlWU85NmZHMlFuUkNDdXM2bEpIYXFuZEFWTy05U1ZvLTZuNUE2bXl2NHlHR1VENlJDOGJEVVBUbEhlaVE0dkVFY3l3cGlaVGJNTFRuYjZENEFITU9Ya1E3cGhTODdfRHljdE02d2ZqWURNa0dBcWhObkNPSmFNT2ZtaXZlb1lrVTc1cjZNSnRucnF2TE85SmcxcUNXLXBsdzhvcFFNS0g5VzBxRTV2Zzg3RkhzSzNJSW1zVGNCT2k4MnN6aV9namtDbnV5Q0Z5MWo3SkVMNWgzUXZtMUlsR0U5T3VLMW5QWVZ2bXVxSzd4bU1vNVNSd0ZzNTR3WS1nN01jaEszNjZuRG9kSlFWRlEtckF4SUZtMDBdLS0+PC9nPjwvc3ZnPg==" /></p>
<p><em>Note: a scope is “open” if its current state is unused, open, or
open-and-joining; a scope is “closed” if its current state is closed,
unused-and-closed, closed-and-joining, or joined.</em></p>
<p>Instances start in the unused state after being constructed. This is
the only time the scope’s state can be set to unused. When the
<code class="sourceCode default">simple_counting_scope</code> destructor
starts, the scope must be in the unused, unused-and-closed, or joined
state; otherwise, the destructor invokes
<code class="sourceCode default">std::terminate()</code>. Permitting
destruction when the scope is in the unused or unused-and-closed state
ensures that instances of
<code class="sourceCode default">simple_counting_scope</code> can be
used safely as data-members while preserving structured
functionality.</p>
<p>Connecting and starting a
<em><code class="sourceCode default">join-sender</code></em> returned
from <code class="sourceCode default">join()</code> moves the scope to
either the open-and-joining or closed-and-joining state. Merely calling
<code class="sourceCode default">join()</code> or connecting the
<em><code class="sourceCode default">join-sender</code></em> does not
change the scope’s state—the
<em><code class="sourceCode default">operation-state</code></em> must be
started to effect the state change. A started
<em><code class="sourceCode default">join-sender</code></em> completes
when the scope’s count of outstanding operations reaches zero, at which
point the scope transitions to the joined state.</p>
<p>Calling <code class="sourceCode default">close()</code> on a
<code class="sourceCode default">simple_counting_scope</code> moves the
scope to the closed, unused-and-closed, or closed-and-joining state, and
causes all future calls to
<code class="sourceCode default">nest()</code> to fail.</p>
<p>Any call to <code class="sourceCode default">nest()</code> may throw
an exception if copying or moving the input sender into the returned
<em><code class="sourceCode default">nest-sender</code></em> throws an
exception. <code class="sourceCode default">nest()</code> provides the
Strong Exception Guarantee so the scope’s state is left unchanged if an
exception is thrown while constructing the returned
<em><code class="sourceCode default">nest-sender</code></em>.</p>
<p>Assuming <code class="sourceCode default">nest()</code> does not
throw:</p>
<ul>
<li>While a scope is in the unused, open, or open-and-joining state,
calls to <code class="sourceCode default">nest()</code> succeed by
returning an “associated sender” (see below) and incrementing the
scope’s count of outstanding operations <em>before returning</em>.</li>
<li>While a scope is in the closed, unused-and-closed,
closed-and-joining, or joined state, calls to
<code class="sourceCode default">nest()</code> fail by returning an
“unassociated sender” (see below). Failed calls to
<code class="sourceCode default">nest()</code> do <em>not</em> increment
the scope’s count of outstanding operations.</li>
</ul>
<p>While a scope is open, calls to
<code class="sourceCode default">nest()</code> that return normally will
have incremented the scope’s count of oustanding operations. In this
case, the resulting
<em><code class="sourceCode default">nest-sender</code></em> is an
associated sender that acts like an RAII handle: the scope’s internal
count is incremented when the sender is created and decremented when the
sender is “done with the scope”, which happens when the sender or its
<em><code class="sourceCode default">operation-state</code></em> is
destroyed. Moving a
<em><code class="sourceCode default">nest-sender</code></em> transfers
responsibility for decrementing the count from the old instance to the
new one. Copying an associated
<em><code class="sourceCode default">nest-sender</code></em> is
permitted if the sender it’s wrapping is copyable, but the copy may
“fail” since copying requires incrementing the scope’s count, which is
only allowed when the scope is open; if copying fails, the new sender is
an unassociated sender that behaves as if it were the result of a failed
call to <code class="sourceCode default">nest()</code>.</p>
<p>While a scope is closed, calls to
<code class="sourceCode default">nest()</code> that return normally will
have failed to increment the scope’s count of outstanding operations or
otherwise change the scope’s state. In this case, the resulting
<em><code class="sourceCode default">nest-sender</code></em> is an
unassociated sender. Unassociated
<em><code class="sourceCode default">nest-senders</code></em> do not
have a reference to the scope they came from and always complete with
<code class="sourceCode default">stopped</code> when connected and
started. Copying or moving an unassociated sender produces another
unassociated sender.</p>
<p>Under the standard assumption that the arguments to
<code class="sourceCode default">nest()</code> are and remain valid
while evaluating <code class="sourceCode default">nest()</code>, it is
always safe to invoke any supported operation on the returned
<em><code class="sourceCode default">nest-sender</code></em>.</p>
<p>The state transitions of a
<code class="sourceCode default">simple_counting_scope</code> mean that
it can be used to protect asynchronous work from use-after-free errors.
Given a resource, <code class="sourceCode default">res</code>, and a
<code class="sourceCode default">simple_counting_scope</code>,
<code class="sourceCode default">scope</code>, obeying the following
policy is enough to ensure that there are no attempts to use
<code class="sourceCode default">res</code> after its lifetime ends:</p>
<ul>
<li>all senders that refer to
<code class="sourceCode default">res</code> are nested within
<code class="sourceCode default">scope</code>; and</li>
<li><code class="sourceCode default">scope</code> is destroyed (and
therefore in the joined, unused, or unused-and-closed state) before
<code class="sourceCode default">res</code> is destroyed.</li>
</ul>
<p>It is safe to destroy a scope in the unused or unusued-and-closed
state because there can’t be any work referring to the resources
protected by the scope.</p>
<p>A <code class="sourceCode default">simple_counting_scope</code> is
uncopyable and immovable so its copy and move operators are explicitly
deleted. <code class="sourceCode default">simple_counting_scope</code>
could be made movable but it would cost an allocation so this is not
proposed.</p>
<h3 data-number="5.6.1" id="simple_counting_scopesimple_counting_scope"><span class="header-section-number">5.6.1</span> <code class="sourceCode default">simple_counting_scope::simple_counting_scope</code><a href="#simple_counting_scopesimple_counting_scope" class="self-link"></a></h3>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a>simple_counting_scope<span class="op">::</span>simple_counting_scope<span class="op">()</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p>Initializes a
<code class="sourceCode default">simple_counting_scope</code> in the
unused state with the count of outstanding operations set to zero.</p>
<h3 data-number="5.6.2" id="simple_counting_scopesimple_counting_scope-1"><span class="header-section-number">5.6.2</span> <code class="sourceCode default">simple_counting_scope::~simple_counting_scope</code><a href="#simple_counting_scopesimple_counting_scope-1" class="self-link"></a></h3>
<div class="sourceCode" id="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a>simple_counting_scope<span class="op">::~</span>simple_counting_scope<span class="op">()</span>;</span></code></pre></div>
<p>Checks that the
<code class="sourceCode default">simple_counting_scope</code> is in the
joined, unused, or unused-and-closed state and invokes
<code class="sourceCode default">std::terminate()</code> if not.</p>
<h3 data-number="5.6.3" id="simple_counting_scopeget_token"><span class="header-section-number">5.6.3</span>
<code class="sourceCode default">simple_counting_scope::get_token</code><a href="#simple_counting_scopeget_token" class="self-link"></a></h3>
<div class="sourceCode" id="cb29"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a>simple_counting_scope<span class="op">::</span>token get_token<span class="op">()</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p>Returns a
<code class="sourceCode default">simple_counting_scope::token</code>
referring to the current scope, as if by invoking
<code class="sourceCode default">token{this}</code>.</p>
<h3 data-number="5.6.4" id="simple_counting_scopeclose"><span class="header-section-number">5.6.4</span>
<code class="sourceCode default">simple_counting_scope::close</code><a href="#simple_counting_scopeclose" class="self-link"></a></h3>
<div class="sourceCode" id="cb30"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> close<span class="op">()</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p>Moves the scope to the closed, unused-and-closed, or
closed-and-joining state. After a call to
<code class="sourceCode default">close()</code>, all future calls to
<code class="sourceCode default">nest()</code> that return normally
return unassociated senders.</p>
<h3 data-number="5.6.5" id="simple_counting_scopejoin"><span class="header-section-number">5.6.5</span>
<code class="sourceCode default">simple_counting_scope::join</code><a href="#simple_counting_scopejoin" class="self-link"></a></h3>
<div class="sourceCode" id="cb31"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>join-sender</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a><em>join-sender</em> join<span class="op">()</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p>Returns a
<em><code class="sourceCode default">join-sender</code></em>. When the
<em><code class="sourceCode default">join-sender</code></em> is
connected to a receiver, <code class="sourceCode default">r</code>, it
produces an
<em><code class="sourceCode default">operation-state</code></em>,
<code class="sourceCode default">o</code>. When
<code class="sourceCode default">o</code> is started, the scope moves to
either the open-and-joining or closed-and-joining state.
<code class="sourceCode default">o</code> completes with
<code class="sourceCode default">set_value()</code> when the scope moves
to the joined state, which happens when the scope’s count of outstanding
senders drops to zero. <code class="sourceCode default">o</code> may
complete synchronously if it happens to observe that the count of
outstanding senders is already zero when started; otherwise,
<code class="sourceCode default">o</code> completes on the execution
context associated with the scheduler in its receiver’s environment by
asking its receiver, <code class="sourceCode default">r</code>, for a
scheduler, <code class="sourceCode default">sch</code>, with
<code class="sourceCode default">get_scheduler(get_env(r))</code> and
then starting the sender returned from
<code class="sourceCode default">schedule(sch)</code>. This requirement
to complete on the receiver’s scheduler restricts which receivers a
<em><code class="sourceCode default">join-sender</code></em> may be
connected to in exchange for determinism; the alternative would have the
<em><code class="sourceCode default">join-sender</code></em> completing
on the execution context of whichever nested operation happens to be the
last one to complete.</p>
<h3 data-number="5.6.6" id="simple_counting_scopetokennest"><span class="header-section-number">5.6.6</span> <code class="sourceCode default">simple_counting_scope::token::nest</code><a href="#simple_counting_scopetokennest" class="self-link"></a></h3>
<div class="sourceCode" id="cb32"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender S<span class="op">&gt;</span></span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>nest-sender</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender S<span class="op">&gt;</span></span>
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a><em>nest-sender</em><span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>S<span class="op">&gt;&gt;</span> nest<span class="op">(</span>S<span class="op">&amp;&amp;</span> s<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span><span class="op">(</span></span>
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>is_nothrow_constructible_v<span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>S<span class="op">&gt;</span>, S<span class="op">&gt;)</span>;</span></code></pre></div>
<p>Attempts to return an associated
<em><code class="sourceCode default">nest-sender</code></em> constructed
from <code class="sourceCode default">s</code>. The attempt will be
successful if and only if:</p>
<ul>
<li>copying or moving (as appropriate)
<code class="sourceCode default">s</code> into the
<em><code class="sourceCode default">nest-sender</code></em> does not
throw an exception, and</li>
<li>the token’s scope’s state can be successfully updated as described
below.</li>
</ul>
<p>If construction of the
<em><code class="sourceCode default">nest-sender</code></em> throws, the
scope’s state is left unchanged. Otherwise, the following atomic state
change is attempted on the token’s scope:</p>
<ul>
<li>increment the scope’s count of outstanding operations; and</li>
<li>move the scope to the open state if it was in the unused state.</li>
</ul>
<p>The atomic state change succeeds if the scope is observed to be in
the unused, open, or open-and-joining state; otherwise it fails.</p>
<p>If the atomic state change fails then the return value is an
unassociated
<em><code class="sourceCode default">nest-sender</code></em>.</p>
<p>An associated
<em><code class="sourceCode default">nest-sender</code></em> is a kind
of RAII handle to the scope; it is responsible for decrementing the
scope’s count of outstanding senders in its destructor unless that
responsibility is first given to some other object. Move-construction
and move-assignment transfer the decrement responsibility to the
destination instance. Connecting an instance to a receiver transfers the
decrement responsibility to the resulting
<em><code class="sourceCode default">operation-state</code></em>; that
<em><code class="sourceCode default">operation-state</code></em>’s
destructor must destroy its “child operation” (i.e. the
<em><code class="sourceCode default">operation-state</code></em>
constructed when connecting the sender,
<code class="sourceCode default">s</code>, that was originally passed to
<code class="sourceCode default">nest()</code>) before performing the
decrement.</p>
<p>Note: the timing of when an
<em><code class="sourceCode default">operation-state</code></em>
decrements the scope’s count is chosen to avoid exposing user code to
dangling references. Decrementing the scope’s count may move the scope
to the joined state, which would allow the waiting
<em><code class="sourceCode default">join-sender</code></em> to
complete, potentially leading to the destruction of a resource protected
by the scope. In general, it’s possible that the
<em><code class="sourceCode default">nest-sender</code></em>’s receiver
or the child operation’s destructor may dereference pointers to the
protected resource so their execution must be completed before the scope
moves to the joined state.</p>
<p>Whenever the balancing decrement happens, it’s possible that the
scope has transitioned to the open-and-joining or closed-and-joining
state since the
<em><code class="sourceCode default">nest-sender</code></em> was
constructed, which means that there is a
<em><code class="sourceCode default">join-sender</code></em> waiting to
complete. If the decrement brings the count of outstanding operations to
zero then the waiting
<em><code class="sourceCode default">join-sender</code></em> must be
notified that the scope is now joined and the sender can complete.</p>
<p>A call to <code class="sourceCode default">nest()</code> does not
start the given sender. A call to
<code class="sourceCode default">nest()</code> is not expected to incur
allocations other than whatever might be required to move or copy
<code class="sourceCode default">s</code>.</p>
<p>Similar to <code class="sourceCode default">spawn_future()</code>,
<code class="sourceCode default">nest()</code> doesn’t constrain the
input sender to any specific shape. Any type of sender is accepted.</p>
<p>As <code class="sourceCode default">nest()</code> does not
immediately start the given work, it is ok to pass in blocking
senders.</p>
<p>Usage example:</p>
<div class="sourceCode" id="cb33"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a>sender <span class="kw">auto</span> example<span class="op">(</span>simple_counting_scope<span class="op">::</span>token token, scheduler <span class="kw">auto</span> sched<span class="op">)</span> <span class="op">{</span></span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a>  sender <span class="kw">auto</span> snd <span class="op">=</span> nest<span class="op">(</span>key_work<span class="op">()</span>, token<span class="op">)</span>;</span>
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> <span class="dv">10</span>; i<span class="op">++)</span></span>
<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a>    spawn<span class="op">(</span>on<span class="op">(</span>sched, other_work<span class="op">(</span>i<span class="op">))</span>, token<span class="op">)</span>;</span>
<span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> on<span class="op">(</span>sched, std<span class="op">::</span>move<span class="op">(</span>snd<span class="op">))</span>;</span>
<span id="cb33-8"><a href="#cb33-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="5.7" id="executioncounting_scope"><span class="header-section-number">5.7</span>
<code class="sourceCode default">execution::counting_scope</code><a href="#executioncounting_scope" class="self-link"></a></h2>
<div class="sourceCode" id="cb34"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> counting_scope <span class="op">{</span></span>
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a>    counting_scope<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">~</span>counting_scope<span class="op">()</span>;</span>
<span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-5"><a href="#cb34-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">// counting_scope is immovable and uncopyable</span></span>
<span id="cb34-6"><a href="#cb34-6" aria-hidden="true" tabindex="-1"></a>    counting_scope<span class="op">(</span><span class="kw">const</span> counting_scope<span class="op">&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb34-7"><a href="#cb34-7" aria-hidden="true" tabindex="-1"></a>    counting_scope<span class="op">(</span>counting_scope<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb34-8"><a href="#cb34-8" aria-hidden="true" tabindex="-1"></a>    counting_scope<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span><span class="kw">const</span> counting_scope<span class="op">&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb34-9"><a href="#cb34-9" aria-hidden="true" tabindex="-1"></a>    counting_scope<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span>counting_scope<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb34-10"><a href="#cb34-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-11"><a href="#cb34-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span>sender S<span class="op">&gt;</span></span>
<span id="cb34-12"><a href="#cb34-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> <em>nest-sender</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb34-13"><a href="#cb34-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-14"><a href="#cb34-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> token <span class="op">{</span></span>
<span id="cb34-15"><a href="#cb34-15" aria-hidden="true" tabindex="-1"></a>      <span class="kw">template</span> <span class="op">&lt;</span>sender S<span class="op">&gt;</span></span>
<span id="cb34-16"><a href="#cb34-16" aria-hidden="true" tabindex="-1"></a>      <em>nest-sender</em><span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>S<span class="op">&gt;&gt;</span> nest<span class="op">(</span>S<span class="op">&amp;&amp;</span> s<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb34-17"><a href="#cb34-17" aria-hidden="true" tabindex="-1"></a>          <span class="kw">noexcept</span><span class="op">(</span>std<span class="op">::</span>is_nothrow_constructible_v<span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>S<span class="op">&gt;</span>, S<span class="op">&gt;)</span>;</span>
<span id="cb34-18"><a href="#cb34-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-19"><a href="#cb34-19" aria-hidden="true" tabindex="-1"></a>     <span class="kw">private</span><span class="op">:</span></span>
<span id="cb34-20"><a href="#cb34-20" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> counting_scope;</span>
<span id="cb34-21"><a href="#cb34-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-22"><a href="#cb34-22" aria-hidden="true" tabindex="-1"></a>      <span class="kw">explicit</span> token<span class="op">(</span>counting_scope<span class="op">*</span> s<span class="op">)</span> <span class="kw">noexcept</span>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb34-23"><a href="#cb34-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-24"><a href="#cb34-24" aria-hidden="true" tabindex="-1"></a>      counting_scope<span class="op">*</span> scope; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb34-25"><a href="#cb34-25" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb34-26"><a href="#cb34-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-27"><a href="#cb34-27" aria-hidden="true" tabindex="-1"></a>    token get_token<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb34-28"><a href="#cb34-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-29"><a href="#cb34-29" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> close<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb34-30"><a href="#cb34-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-31"><a href="#cb34-31" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> request_stop<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb34-32"><a href="#cb34-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-33"><a href="#cb34-33" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> <em>join-sender</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb34-34"><a href="#cb34-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-35"><a href="#cb34-35" aria-hidden="true" tabindex="-1"></a>    <em>join-sender</em> join<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb34-36"><a href="#cb34-36" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>A <code class="sourceCode default">counting_scope</code> augments a
<code class="sourceCode default">simple_counting_scope</code> with a
stop source and gives to each of its associated
<em><code class="sourceCode default">nest-senders</code></em> a stop
token from its stop source. This extension of
<code class="sourceCode default">simple_counting_scope</code> allows a
<code class="sourceCode default">counting_scope</code> to request stop
on all of its outstanding operations by requesting stop on its stop
source.</p>
<p>Assuming an exposition-only <em><code class="sourceCode default">stop_when(sender auto&amp;&amp;, stoppable_token auto)</code></em>
(explained below),
<code class="sourceCode default">counting_scope</code> behaves as if it
were implemented like so:</p>
<div class="sourceCode" id="cb35"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> counting_scope <span class="op">{</span></span>
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> token <span class="op">{</span></span>
<span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span>sender S<span class="op">&gt;</span></span>
<span id="cb35-4"><a href="#cb35-4" aria-hidden="true" tabindex="-1"></a>    sender <span class="kw">auto</span> nest<span class="op">(</span>S<span class="op">&amp;&amp;</span> snd<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb35-5"><a href="#cb35-5" aria-hidden="true" tabindex="-1"></a>        <span class="kw">noexcept</span><span class="op">(</span>std<span class="op">::</span>is_nothrow_constructible_v<span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>S<span class="op">&gt;</span>, S<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb35-6"><a href="#cb35-6" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> std<span class="op">::</span>forward<span class="op">&lt;</span>Sender<span class="op">&gt;(</span>snd<span class="op">)</span></span>
<span id="cb35-7"><a href="#cb35-7" aria-hidden="true" tabindex="-1"></a>          <span class="op">|</span> <em>stop_when</em><span class="op">(</span>scope_<span class="op">-&gt;</span>source_<span class="op">.</span>get_token<span class="op">())</span></span>
<span id="cb35-8"><a href="#cb35-8" aria-hidden="true" tabindex="-1"></a>          <span class="op">|</span> ex<span class="op">::</span>nest<span class="op">(</span>scope_<span class="op">-&gt;</span>scope_<span class="op">.</span>get_token<span class="op">())</span>;</span>
<span id="cb35-9"><a href="#cb35-9" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb35-10"><a href="#cb35-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb35-11"><a href="#cb35-11" aria-hidden="true" tabindex="-1"></a>   <span class="kw">private</span><span class="op">:</span></span>
<span id="cb35-12"><a href="#cb35-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">friend</span> counting_scope;</span>
<span id="cb35-13"><a href="#cb35-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb35-14"><a href="#cb35-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">explicit</span> token<span class="op">(</span>counting_scope<span class="op">*</span> scope<span class="op">)</span> <span class="kw">noexcept</span></span>
<span id="cb35-15"><a href="#cb35-15" aria-hidden="true" tabindex="-1"></a>      <span class="op">:</span> scope_<span class="op">(</span>scope<span class="op">)</span> <span class="op">{}</span></span>
<span id="cb35-16"><a href="#cb35-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb35-17"><a href="#cb35-17" aria-hidden="true" tabindex="-1"></a>    counting_scope<span class="op">*</span> scope_;</span>
<span id="cb35-18"><a href="#cb35-18" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb35-19"><a href="#cb35-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb35-20"><a href="#cb35-20" aria-hidden="true" tabindex="-1"></a>  token get_token<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb35-21"><a href="#cb35-21" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> token<span class="op">{</span><span class="kw">this</span><span class="op">}</span>;</span>
<span id="cb35-22"><a href="#cb35-22" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb35-23"><a href="#cb35-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb35-24"><a href="#cb35-24" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> close<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb35-25"><a href="#cb35-25" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> scope_<span class="op">.</span>close<span class="op">()</span>;</span>
<span id="cb35-26"><a href="#cb35-26" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb35-27"><a href="#cb35-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb35-28"><a href="#cb35-28" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> request_stop<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb35-29"><a href="#cb35-29" aria-hidden="true" tabindex="-1"></a>    source_<span class="op">.</span>request_stop<span class="op">()</span>;</span>
<span id="cb35-30"><a href="#cb35-30" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb35-31"><a href="#cb35-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb35-32"><a href="#cb35-32" aria-hidden="true" tabindex="-1"></a>  sender <span class="kw">auto</span> join<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb35-33"><a href="#cb35-33" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> scope_<span class="op">.</span>join<span class="op">()</span>;</span>
<span id="cb35-34"><a href="#cb35-34" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb35-35"><a href="#cb35-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb35-36"><a href="#cb35-36" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span><span class="op">:</span></span>
<span id="cb35-37"><a href="#cb35-37" aria-hidden="true" tabindex="-1"></a>  simple_counting_scope scope_;</span>
<span id="cb35-38"><a href="#cb35-38" aria-hidden="true" tabindex="-1"></a>  inplace_stop_source source_;</span>
<span id="cb35-39"><a href="#cb35-39" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p><em><code class="sourceCode default">stop_when(sender auto&amp;&amp; snd, stoppable_token auto stoken)</code></em>
is an exposition-only sender algorithm that maps its input sender,
<code class="sourceCode default">snd</code>, to an output sender,
<code class="sourceCode default">osnd</code>, such that, when
<code class="sourceCode default">osnd</code> is connected to a receiver,
<code class="sourceCode default">r</code>, the resulting
<em><code class="sourceCode default">operation-state</code></em> behaves
the same as connecting the original sender,
<code class="sourceCode default">snd</code>, to
<code class="sourceCode default">r</code>, except that
<code class="sourceCode default">snd</code> will receive a stop request
when either the token returned from
<code class="sourceCode default">get_stop_token(r)</code> receives a
stop request or when <code class="sourceCode default">stoken</code>
receives a stop request.</p>
<p>Other than the use of
<em><code class="sourceCode default">stop_when()</code></em> in
<code class="sourceCode default">counting_scope::token::nest()</code>
and the addition of
<code class="sourceCode default">request_stop()</code> to the interface,
<code class="sourceCode default">counting_scope</code> has the same
behavior and lifecycle as
<code class="sourceCode default">simple_counting_scope</code>.</p>
<h3 data-number="5.7.1" id="counting_scopecounting_scope"><span class="header-section-number">5.7.1</span>
<code class="sourceCode default">counting_scope::counting_scope</code><a href="#counting_scopecounting_scope" class="self-link"></a></h3>
<div class="sourceCode" id="cb36"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a>counting_scope<span class="op">::</span>counting_scope<span class="op">()</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p>Initializes a <code class="sourceCode default">counting_scope</code>
in the unused state with the count of outstanding operations set to
zero.</p>
<h3 data-number="5.7.2" id="counting_scopecounting_scope-1"><span class="header-section-number">5.7.2</span>
<code class="sourceCode default">counting_scope::~counting_scope</code><a href="#counting_scopecounting_scope-1" class="self-link"></a></h3>
<div class="sourceCode" id="cb37"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a>counting_scope<span class="op">::~</span>counting_scope<span class="op">()</span>;</span></code></pre></div>
<p>Checks that the
<code class="sourceCode default">counting_scope</code> is in the joined,
unused, or unused-and-closed state and invokes
<code class="sourceCode default">std::terminate()</code> if not.</p>
<h3 data-number="5.7.3" id="counting_scopeget_token"><span class="header-section-number">5.7.3</span>
<code class="sourceCode default">counting_scope::get_token</code><a href="#counting_scopeget_token" class="self-link"></a></h3>
<div class="sourceCode" id="cb38"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a>counting_scope<span class="op">::</span>token get_token<span class="op">()</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p>Returns a
<code class="sourceCode default">counting_scope::token</code> referring
to the current scope, as if by invoking
<code class="sourceCode default">token{this}</code>.</p>
<h3 data-number="5.7.4" id="counting_scopeclose"><span class="header-section-number">5.7.4</span>
<code class="sourceCode default">counting_scope::close</code><a href="#counting_scopeclose" class="self-link"></a></h3>
<div class="sourceCode" id="cb39"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> close<span class="op">()</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p>Moves the scope to the closed, unused-and-closed, or
closed-and-joining state. After a call to
<code class="sourceCode default">close()</code>, all future calls to
<code class="sourceCode default">nest()</code> that return normally
return unassociated senders.</p>
<h3 data-number="5.7.5" id="counting_scoperequest_stop"><span class="header-section-number">5.7.5</span>
<code class="sourceCode default">counting_scope::request_stop</code><a href="#counting_scoperequest_stop" class="self-link"></a></h3>
<div class="sourceCode" id="cb40"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> request_stop<span class="op">()</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p>Requests stop on the scope’s internal stop source. Since all senders
nested within the scope have been given stop tokens from this internal
stop source, the effect is to send stop requests to all outstanding (and
future) nested operations.</p>
<h3 data-number="5.7.6" id="counting_scopejoin"><span class="header-section-number">5.7.6</span>
<code class="sourceCode default">counting_scope::join</code><a href="#counting_scopejoin" class="self-link"></a></h3>
<div class="sourceCode" id="cb41"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>join-sender</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a><em>join-sender</em> join<span class="op">()</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p>Returns a
<em><code class="sourceCode default">join-sender</code></em> that
behaves the same as the result of
<code class="sourceCode default">simple_counting_scope::join()</code>.
Connecting and starting the
<em><code class="sourceCode default">join-sender</code></em> moves the
scope to the open-and-joining or closed-and-joining state; the
<em><code class="sourceCode default">join-sender</code></em> completes
when the scope’s count of outstanding operations drops to zero, at which
point the scope moves to the joined state.</p>
<h3 data-number="5.7.7" id="counting_scopetokennest"><span class="header-section-number">5.7.7</span>
<code class="sourceCode default">counting_scope::token::nest</code><a href="#counting_scopetokennest" class="self-link"></a></h3>
<div class="sourceCode" id="cb42"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender S<span class="op">&gt;</span></span>
<span id="cb42-2"><a href="#cb42-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>nest-sender</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb42-3"><a href="#cb42-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb42-4"><a href="#cb42-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender S<span class="op">&gt;</span></span>
<span id="cb42-5"><a href="#cb42-5" aria-hidden="true" tabindex="-1"></a><em>nest-sender</em><span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>S<span class="op">&gt;&gt;</span> nest<span class="op">(</span>S<span class="op">&amp;&amp;</span> s<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span><span class="op">(</span></span>
<span id="cb42-6"><a href="#cb42-6" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>is_nothrow_constructible_v<span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>S<span class="op">&gt;</span>, S<span class="op">&gt;)</span>;</span></code></pre></div>
<p>Attempts to return an associated
<em><code class="sourceCode default">nest-sender</code></em> constructed
from <code class="sourceCode default">s</code> following the same
algorithm as <code class="sourceCode default">simple_counting_scope::token::nest()</code>,
with the addition that senders associated with a
<code class="sourceCode default">counting_scope</code> receive stop
requests <em>both</em> from their (eventual) receivers <em>and</em> from
the <code class="sourceCode default">counting_scope</code>’s internal
stop source.</p>
<h2 data-number="5.8" id="when-to-use-counting_scope-vs-p3296r0s-let_with_async_scope"><span class="header-section-number">5.8</span> When to use
<code class="sourceCode default">counting_scope</code> vs <span class="citation" data-cites="P3296R0">[<a href="#ref-P3296R0" role="doc-biblioref">P3296R0</a>]</span>’s
<code class="sourceCode default">let_with_async_scope</code><a href="#when-to-use-counting_scope-vs-p3296r0s-let_with_async_scope" class="self-link"></a></h2>
<p>Although <code class="sourceCode default">counting_scope</code> and
<code class="sourceCode default">let_with_async_scope</code> have
overlapping use-cases, we specifically designed the two facilities to
address separate problems. In short,
<code class="sourceCode default">counting_scope</code> is best used in
an unstructured context and
<code class="sourceCode default">let_with_async_scope</code> is best
used in a structured context.</p>
<p>We define “unstructured context” as:</p>
<ul>
<li>a place where using
<code class="sourceCode default">sync_wait</code> would be
inappropriate,</li>
<li>and you can’t “solve by induction” (i.e you’re not in an async
context where you can start the sender by “awaiting” it)</li>
</ul>
<p><code class="sourceCode default">counting_scope</code> should be used
when you have a sender you want to start in an unstructured context. In
this case,
<code class="sourceCode default">spawn(sender, scope.get_token())</code>
would be the preferred way of starting asynchronous work.
<code class="sourceCode default">scope.join()</code> needs to be called
before the owning object’s destruction in order to ensure that the
object’s lifetime lives at least until all asynchronous work completes.
Note that exception safety needs to be handled explicitly in the use of
<code class="sourceCode default">counting_scope</code>.</p>
<p><code class="sourceCode default">let_with_async_scope</code> returns
a sender, and therefore can only be started in one of 3 ways:</p>
<ol type="1">
<li><code class="sourceCode default">sync_wait</code></li>
<li><code class="sourceCode default">spawn</code> on a
<code class="sourceCode default">counting_scope</code></li>
<li><code class="sourceCode default">co_await</code></li>
</ol>
<p><code class="sourceCode default">let_with_async_scope</code> will
manage the scope for you, ensuring that the managed scope is always
joined before
<code class="sourceCode default">let_with_async_scope</code> completes.
The algorithm frees the user from having to manage the coupling between
the lifetimes of the managed scope and the resource(s) it protects with
the limitation that the nested work must be fully structured. This
behavior is a feature, since the scope being managed by
<code class="sourceCode default">let_with_async_scope</code> is intended
to live only until the sender completes. This also means that
<code class="sourceCode default">let_with_async_scope</code> will be
exception safe by default.</p>
<h1 data-number="6" id="design-considerations"><span class="header-section-number">6</span> Design considerations<a href="#design-considerations" class="self-link"></a></h1>
<h2 data-number="6.1" id="shape-of-the-given-sender"><span class="header-section-number">6.1</span> Shape of the given sender<a href="#shape-of-the-given-sender" class="self-link"></a></h2>
<h3 data-number="6.1.1" id="constraints-on-set_value"><span class="header-section-number">6.1.1</span> Constraints on
<code class="sourceCode default">set_value()</code><a href="#constraints-on-set_value" class="self-link"></a></h3>
<p>It makes sense for
<code class="sourceCode default">spawn_future()</code> and
<code class="sourceCode default">nest()</code> to accept senders with
any type of completion signatures. The caller gets back a sender that
can be chained with other senders, and it doesn’t make sense to restrict
the shape of this sender.</p>
<p>The same reasoning doesn’t necessarily follow for
<code class="sourceCode default">spawn()</code> as it returns
<code class="sourceCode default">void</code> and the result of the
spawned sender is dropped. There are two main alternatives:</p>
<ul>
<li>do not constrain the shape of the input sender (i.e., dropping the
results of the computation)</li>
<li>constrain the shape of the input sender</li>
</ul>
<p>The current proposal goes with the second alternative. The main
reason is to make it more difficult and explicit to silently drop
results. The caller can always transform the input sender before passing
it to <code class="sourceCode default">spawn()</code> to drop the values
manually.</p>
<blockquote>
<p><strong>Chosen:</strong>
<code class="sourceCode default">spawn()</code> accepts only senders
that advertise <code class="sourceCode default">set_value()</code>
(without any parameters) in the completion signatures.</p>
</blockquote>
<h3 data-number="6.1.2" id="handling-errors-in-spawn"><span class="header-section-number">6.1.2</span> Handling errors in
<code class="sourceCode default">spawn()</code><a href="#handling-errors-in-spawn" class="self-link"></a></h3>
<p>The current proposal does not accept senders that can complete with
error given to <code class="sourceCode default">spawn()</code>. This
will prevent accidental error scenarios that will terminate the
application. The user must deal with all possible errors before passing
the sender to <code class="sourceCode default">spawn()</code>. i.e.,
error handling must be explicit.</p>
<p>Another alternative considered was to call
<code class="sourceCode default">std::terminate()</code> when the sender
completes with error.</p>
<p>Another alternative is to silently drop the errors when receiving
them. This is considered bad practice, as it will often lead to first
spotting bugs in production.</p>
<blockquote>
<p><strong>Chosen:</strong>
<code class="sourceCode default">spawn()</code> accepts only senders
that do not call <code class="sourceCode default">set_error()</code>.
Explicit error handling is preferred over stopping the application, and
over silently ignoring the error.</p>
</blockquote>
<h3 data-number="6.1.3" id="handling-stop-signals-in-spawn"><span class="header-section-number">6.1.3</span> Handling stop signals in
<code class="sourceCode default">spawn()</code><a href="#handling-stop-signals-in-spawn" class="self-link"></a></h3>
<p>Similar to the error case, we have the alternative of allowing or
forbidding <code class="sourceCode default">set_stopped()</code> as a
completion signal. Because the goal of
<code class="sourceCode default">counting_scope</code> is to track the
lifetime of the work started through it, it shouldn’t matter whether
that the work completed with success or by being stopped. As it is
assumed that sending the stop signal is the result of an explicit
choice, it makes sense to allow senders that can terminate with
<code class="sourceCode default">set_stopped()</code>.</p>
<p>The alternative would require transforming the sender before passing
it to spawn, something like <code class="sourceCode default">spawn(std::move(snd) | let_stopped(just), s.get_token())</code>.
This is considered boilerplate and not helpful, as the stopped scenarios
should be implicit, and not require handling.</p>
<blockquote>
<p><strong>Chosen:</strong>
<code class="sourceCode default">spawn()</code> accepts senders that
complete with <code class="sourceCode default">set_stopped()</code>.</p>
</blockquote>
<h3 data-number="6.1.4" id="no-shape-restrictions-for-the-senders-passed-to-spawn_future-and-nest"><span class="header-section-number">6.1.4</span> No shape restrictions for the
senders passed to <code class="sourceCode default">spawn_future()</code>
and <code class="sourceCode default">nest()</code><a href="#no-shape-restrictions-for-the-senders-passed-to-spawn_future-and-nest" class="self-link"></a></h3>
<p>Similarly to <code class="sourceCode default">spawn()</code>, we can
constrain <code class="sourceCode default">spawn_future()</code> and
<code class="sourceCode default">nest()</code> to accept only a limited
set of senders. But, because we can attach continuations for these
senders, we would be limiting the functionality that can be expressed.
For example, the continuation can handle different types of values and
errors.</p>
<blockquote>
<p><strong>Chosen:</strong>
<code class="sourceCode default">spawn_future()</code> and
<code class="sourceCode default">nest()</code> accept senders with any
completion signatures.</p>
</blockquote>
<h2 data-number="6.2" id="p2300s-start_detached"><span class="header-section-number">6.2</span> P2300’s
<code class="sourceCode default">start_detached()</code><a href="#p2300s-start_detached" class="self-link"></a></h2>
<p>The <code class="sourceCode default">spawn()</code> algorithm in this
paper can be used as a replacement for
<code class="sourceCode default">start_detached</code> proposed in <span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span>. Essentially it does the same
thing, but it also provides the given scope the opportunity to apply its
bookkeeping policy to the given sender, which, in the case of
<code class="sourceCode default">counting_scope</code>, ensures the
program can wait for spawned work to complete before destroying any
resources references by that work.</p>
<h2 data-number="6.3" id="p2300s-ensure_started"><span class="header-section-number">6.3</span> P2300’s
<code class="sourceCode default">ensure_started()</code><a href="#p2300s-ensure_started" class="self-link"></a></h2>
<p>The <code class="sourceCode default">spawn_future()</code> algorithm
in this paper can be used as a replacement for
<code class="sourceCode default">ensure_started</code> proposed in <span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span>. Essentially it does the same
thing, but it also provides the given scope the opportunity to apply its
bookkeeping policy to the given sender, which, in the case of
<code class="sourceCode default">counting_scope</code>, ensures the
program can wait for spawned work to complete before destroying any
resources references by that work.</p>
<h2 data-number="6.4" id="supporting-the-pipe-operator"><span class="header-section-number">6.4</span> Supporting the pipe operator<a href="#supporting-the-pipe-operator" class="self-link"></a></h2>
<p>This paper doesn’t support the pipe operator to be used in
conjunction with <code class="sourceCode default">spawn()</code> and
<code class="sourceCode default">spawn_future()</code>. One might think
that it is useful to write code like the following:</p>
<div class="sourceCode" id="cb43"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb43-1"><a href="#cb43-1" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>move<span class="op">(</span>snd1<span class="op">)</span> <span class="op">|</span> spawn<span class="op">(</span>s<span class="op">)</span>; <span class="co">// returns void</span></span>
<span id="cb43-2"><a href="#cb43-2" aria-hidden="true" tabindex="-1"></a>sender <span class="kw">auto</span> snd3 <span class="op">=</span> std<span class="op">::</span>move<span class="op">(</span>snd2<span class="op">)</span> <span class="op">|</span> spawn_future<span class="op">(</span>s<span class="op">)</span> <span class="op">|</span> then<span class="op">(...)</span>;</span></code></pre></div>
<p>In <span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span> sender
consumers do not have support for the pipe operator. As
<code class="sourceCode default">spawn()</code> works similarly to
<code class="sourceCode default">start_detached()</code> from <span class="citation" data-cites="P2300R7">[<a href="#ref-P2300R7" role="doc-biblioref">P2300R7</a>]</span>, which is a sender consumer, if
we follow the same rationale, it makes sense not to support the pipe
operator for <code class="sourceCode default">spawn()</code>.</p>
<p>On the other hand,
<code class="sourceCode default">spawn_future()</code> is not a sender
consumer, thus we might have considered adding pipe operator to it.</p>
<p>On the third hand, Unifex supports the pipe operator for both of its
equivalent algorithms
(<code class="sourceCode default">unifex::spawn_detached()</code> and
<code class="sourceCode default">unifex::spawn_future()</code>) and
Unifex users have not been confused by this choice.</p>
<p>To keep consistency with
<code class="sourceCode default">spawn()</code> this paper doesn’t
support pipe operator for
<code class="sourceCode default">spawn_future()</code>.</p>
<h2 data-number="6.5" id="problems-protecting-allocators-with-counting_scope"><span class="header-section-number">6.5</span> Problems Protecting Allocators
with <code class="sourceCode default">counting_scope</code><a href="#problems-protecting-allocators-with-counting_scope" class="self-link"></a></h2>
<p>Lewis Baker discovered a problem with using
<code class="sourceCode default">nest()</code> as the basis operation
for implementing <code class="sourceCode default">spawn()</code> when
the <code class="sourceCode default">counting_scope</code> that tracks
the spawned work is being used to protect against accesses to the
allocator provided to <code class="sourceCode default">spawn()</code>
after the allocator has been destroyed. (The problem arises with
<code class="sourceCode default">spawn_future()</code>, too, but we’ll
restrict the discussion to
<code class="sourceCode default">spawn()</code> for simplicity.) We seek
LEWG’s guidance in resolving this problem.</p>
<h3 data-number="6.5.1" id="the-problem"><span class="header-section-number">6.5.1</span> The Problem<a href="#the-problem" class="self-link"></a></h3>
<p>When a spawned operation completes, the order of operations is as
follows:</p>
<ol type="1">
<li>The spawned operation completes by invoking
<code class="sourceCode default">set_value()</code> or
<code class="sourceCode default">set_stopped()</code> on a receiver,
<code class="sourceCode default">rcvr</code>, provided by
<code class="sourceCode default">spawn()</code> to the
<code class="sourceCode default">nest-sender</code>.</li>
<li><code class="sourceCode default">rcvr</code> destroys the
<code class="sourceCode default">nest-sender</code>’s
<em><code class="sourceCode default">operation-state</code></em> by
invoking its destructor.</li>
<li><code class="sourceCode default">rcvr</code> deallocates the storage
previously allocated for the just-destroyed
<em><code class="sourceCode default">operation-state</code></em> using a
copy of the allocator that was chosen when
<code class="sourceCode default">spawn()</code> was invoked. Assume this
allocator was passed to <code class="sourceCode default">spawn()</code>
in the optional environment argument.</li>
</ol>
<p>Note that in step 2, above, the destruction of the
<code class="sourceCode default">nest-sender</code>’s
<em><code class="sourceCode default">operation-state</code></em> has the
side effect of decrementing the associated
<code class="sourceCode default">counting_scope</code>’s count of
outstanding operations. If the scope has a
<code class="sourceCode default">join-sender</code> waiting and this
decrement brings the count to zero, the code waiting on the
<code class="sourceCode default">join-sender</code> to complete may
start to destroy the allocator while step 3 is busy using it.</p>
<h3 data-number="6.5.2" id="some-solutions"><span class="header-section-number">6.5.2</span> Some Solutions<a href="#some-solutions" class="self-link"></a></h3>
<p>We have several options to address the above problem:</p>
<ol type="1">
<li>Do nothing; declare that
<code class="sourceCode default">counting_scope</code> can’t be used to
protect memory allocators.</li>
<li>Remove allocator support from
<code class="sourceCode default">spawn()</code> and
<code class="sourceCode default">spawn_future()</code> and require
allocation with
<code class="sourceCode default">::operator new</code>.</li>
<li>Make <code class="sourceCode default">spawn()</code> and
<code class="sourceCode default">spawn_future()</code> basis operations
of <code class="sourceCode default">async_scope_token</code>s (alongside
<code class="sourceCode default">nest()</code>) so that the derement in
step 2 can be deferred until after step 3 completes.</li>
<li>Define a new set of refcounting basis operations and define
<code class="sourceCode default">nest()</code>,
<code class="sourceCode default">spawn()</code>, and
<code class="sourceCode default">spawn_future()</code> in terms of
them.</li>
<li>Treat <code class="sourceCode default">nest-sender</code>s as RAII
handles to “scope references” and change how
<code class="sourceCode default">spawn()</code> is defined to defer the
decrement. (There are a few implementation possibilities here.)</li>
<li>Give <code class="sourceCode default">async_scope_token</code>s a
new basis operation that can wrap an allocator in a new allocator
wrapper that increments the scope’s refcount in
<code class="sourceCode default">allocate()</code> and decrements it in
<code class="sourceCode default">deallocate()</code>.</li>
</ol>
<p>Recommended: 6.</p>
<h3 data-number="6.5.3" id="discussion-of-reasons-to-reject-options-1-5"><span class="header-section-number">6.5.3</span> Discussion of Reasons to
Reject Options 1-5<a href="#discussion-of-reasons-to-reject-options-1-5" class="self-link"></a></h3>
<p>Option 1 leaves <code class="sourceCode default">spawn()</code> and
<code class="sourceCode default">spawn_future()</code> broken.</p>
<p>Option 2 simplifies the proposal but eliminates support for use cases
requiring custom allocators.</p>
<p>Option 3 adds significant complexity to the task of writing a custom
scope type. Furthermore, there’s another useful algorithm (it’s called
<code class="sourceCode default">detach_on_cancel</code> in Unifex) that
could be added to the Standard later if
<code class="sourceCode default">nest()</code> remains the only basis
operation on scopes, but that probably could never be added if every
scope-related algorithm is a basis operation.</p>
<p>Option 4 is a) unlikely to be ready in time for C++26, and b)
difficult to distinguish from
<code class="sourceCode default">std:shared_ptr&lt;&gt;</code>, which
implementation experience at Meta has proven to be worse than
<code class="sourceCode default">unifex::nest()</code> for
reference-counting async work.</p>
<p>Option 5 is the least-bad of the first five options but it feels
silly. One implementation of
<code class="sourceCode default">spawn()</code> in this option would
look like this:</p>
<div class="sourceCode" id="cb44"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb44-1"><a href="#cb44-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Op, <span class="kw">class</span> Alloc, <span class="kw">class</span> Env, sender Sender<span class="op">&gt;</span></span>
<span id="cb44-2"><a href="#cb44-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> spawn_receiver <span class="op">{</span></span>
<span id="cb44-3"><a href="#cb44-3" aria-hidden="true" tabindex="-1"></a>  Op<span class="op">*</span> op;</span>
<span id="cb44-4"><a href="#cb44-4" aria-hidden="true" tabindex="-1"></a>  Alloc alloc;</span>
<span id="cb44-5"><a href="#cb44-5" aria-hidden="true" tabindex="-1"></a>  Env env;</span>
<span id="cb44-6"><a href="#cb44-6" aria-hidden="true" tabindex="-1"></a>  <span class="co">// in practice, this is a nest-sender that exists solely to hold</span></span>
<span id="cb44-7"><a href="#cb44-7" aria-hidden="true" tabindex="-1"></a>  <span class="co">// a reference on the associated scope until it&#39;s destroyed</span></span>
<span id="cb44-8"><a href="#cb44-8" aria-hidden="true" tabindex="-1"></a>  Sender sender;</span>
<span id="cb44-9"><a href="#cb44-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-10"><a href="#cb44-10" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> set_stopped<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb44-11"><a href="#cb44-11" aria-hidden="true" tabindex="-1"></a>    set_value<span class="op">()</span>;</span>
<span id="cb44-12"><a href="#cb44-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb44-13"><a href="#cb44-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-14"><a href="#cb44-14" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> set_value<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb44-15"><a href="#cb44-15" aria-hidden="true" tabindex="-1"></a>    op<span class="op">-&gt;~</span>Op<span class="op">()</span>;</span>
<span id="cb44-16"><a href="#cb44-16" aria-hidden="true" tabindex="-1"></a>    alloc<span class="op">.</span>deallocate<span class="op">(</span>op, <span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb44-17"><a href="#cb44-17" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb44-18"><a href="#cb44-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-19"><a href="#cb44-19" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> Env<span class="op">&amp;</span> get_env<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb44-20"><a href="#cb44-20" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> env;</span>
<span id="cb44-21"><a href="#cb44-21" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb44-22"><a href="#cb44-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb44-23"><a href="#cb44-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-24"><a href="#cb44-24" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, async_scope_token<span class="op">&lt;</span>Sender<span class="op">&gt;</span> Token, <span class="kw">class</span> Env <span class="op">=</span> empty_env<span class="op">&gt;</span></span>
<span id="cb44-25"><a href="#cb44-25" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> spawn<span class="op">(</span>Sender<span class="op">&amp;&amp;</span> sndr, Token token, Env env <span class="op">=</span> <span class="op">{})</span> <span class="op">{</span></span>
<span id="cb44-26"><a href="#cb44-26" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> nestSender <span class="op">=</span> nest<span class="op">(</span>just<span class="op">()</span>, token<span class="op">)</span>; <span class="co">// try to grab a reference</span></span>
<span id="cb44-27"><a href="#cb44-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-28"><a href="#cb44-28" aria-hidden="true" tabindex="-1"></a>  <span class="co">// assume nest-senders are contextually convertable to bool and convert to false</span></span>
<span id="cb44-29"><a href="#cb44-29" aria-hidden="true" tabindex="-1"></a>  <span class="co">// when they are unassociated (i.e. when the nest failed because the scope is closed)</span></span>
<span id="cb44-30"><a href="#cb44-30" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(!</span>nestSender<span class="op">)</span> <span class="op">{</span></span>
<span id="cb44-31"><a href="#cb44-31" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span>;</span>
<span id="cb44-32"><a href="#cb44-32" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb44-33"><a href="#cb44-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-34"><a href="#cb44-34" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> op_t <span class="op">=</span> connect_result_t<span class="op">&lt;</span>Sender, spawn_receiver<span class="op">&gt;</span>;</span>
<span id="cb44-35"><a href="#cb44-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-36"><a href="#cb44-36" aria-hidden="true" tabindex="-1"></a>  <span class="co">// choose an allocator (either from env, or sndr, or std::allocator&lt;&gt;)</span></span>
<span id="cb44-37"><a href="#cb44-37" aria-hidden="true" tabindex="-1"></a>  <span class="co">// and rebind it to allocate op_ts.</span></span>
<span id="cb44-38"><a href="#cb44-38" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> alloc <span class="op">=</span> choose_allocator<span class="op">&lt;</span>op_t<span class="op">&gt;(</span>env, sndr<span class="op">)</span>;</span>
<span id="cb44-39"><a href="#cb44-39" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-40"><a href="#cb44-40" aria-hidden="true" tabindex="-1"></a>  op_t<span class="op">*</span> op <span class="op">=</span> alloc<span class="op">.</span>allocate<span class="op">(</span><span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb44-41"><a href="#cb44-41" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-42"><a href="#cb44-42" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb44-43"><a href="#cb44-43" aria-hidden="true" tabindex="-1"></a>    <span class="kw">new</span> <span class="op">((</span><span class="dt">void</span><span class="op">)</span>op<span class="op">)</span> op_t<span class="op">{</span></span>
<span id="cb44-44"><a href="#cb44-44" aria-hidden="true" tabindex="-1"></a>        <span class="fu">connect</span><span class="op">(</span>forward<span class="op">&lt;</span>Sender<span class="op">&gt;(</span>sndr<span class="op">)</span>, spawn_receiver<span class="op">{</span>op, alloc, env, move<span class="op">(</span>nestSender<span class="op">)})}</span>;</span>
<span id="cb44-45"><a href="#cb44-45" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb44-46"><a href="#cb44-46" aria-hidden="true" tabindex="-1"></a>  <span class="cf">catch</span> <span class="op">(...)</span> <span class="op">{</span></span>
<span id="cb44-47"><a href="#cb44-47" aria-hidden="true" tabindex="-1"></a>    alloc<span class="op">.</span>deallocate<span class="op">(</span>op, <span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb44-48"><a href="#cb44-48" aria-hidden="true" tabindex="-1"></a>    <span class="cf">throw</span>;</span>
<span id="cb44-49"><a href="#cb44-49" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb44-50"><a href="#cb44-50" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-51"><a href="#cb44-51" aria-hidden="true" tabindex="-1"></a>  op<span class="op">-&gt;</span>start<span class="op">()</span>;</span>
<span id="cb44-52"><a href="#cb44-52" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="6.5.4" id="discussion-of-option-6"><span class="header-section-number">6.5.4</span> Discussion of Option 6<a href="#discussion-of-option-6" class="self-link"></a></h3>
<p>Option 6 amounts to giving
<code class="sourceCode default">async_scope_token</code> a new basis
operation for contructing an allocator wrapper that increments the
associated scope’s reference count in
<code class="sourceCode default">allocate()</code> and decrementing it
in <code class="sourceCode default">deallocate()</code>. If the
following were made valid:</p>
<div class="sourceCode" id="cb45"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb45-1"><a href="#cb45-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> wrapper <span class="op">=</span> scopeToken<span class="op">.</span>wrap_allocator<span class="op">(</span>alloc<span class="op">)</span>;</span></code></pre></div>
<p>then <code class="sourceCode default">spawn()</code> could work like
this:</p>
<div class="sourceCode" id="cb46"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb46-1"><a href="#cb46-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, async_scope_token<span class="op">&lt;</span>Sender<span class="op">&gt;</span> Token, <span class="kw">class</span> Env <span class="op">=</span> empty_env<span class="op">&gt;</span></span>
<span id="cb46-2"><a href="#cb46-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> spawn<span class="op">(</span>Sender<span class="op">&amp;&amp;</span> sndr, Token token, Env env <span class="op">=</span> <span class="op">{})</span> <span class="op">{</span></span>
<span id="cb46-3"><a href="#cb46-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> op_t <span class="op">=</span> connect_result_t<span class="op">&lt;</span>Sender, spawn_receiver<span class="op">&gt;</span>;</span>
<span id="cb46-4"><a href="#cb46-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb46-5"><a href="#cb46-5" aria-hidden="true" tabindex="-1"></a>  <span class="co">// choose an allocator (either from env, or sndr, or std::allocator&lt;&gt;)</span></span>
<span id="cb46-6"><a href="#cb46-6" aria-hidden="true" tabindex="-1"></a>  <span class="co">// and rebind it to allocate op_ts.</span></span>
<span id="cb46-7"><a href="#cb46-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> alloc <span class="op">=</span> token<span class="op">.</span>wrap_allocator<span class="op">(</span>choose_allocator<span class="op">&lt;</span>op_t<span class="op">&gt;(</span>env, sndr<span class="op">))</span>;</span>
<span id="cb46-8"><a href="#cb46-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb46-9"><a href="#cb46-9" aria-hidden="true" tabindex="-1"></a>  <span class="co">// expected to throw std::bad_alloc on failure</span></span>
<span id="cb46-10"><a href="#cb46-10" aria-hidden="true" tabindex="-1"></a>  op_t<span class="op">*</span> op <span class="op">=</span> alloc<span class="op">.</span>allocate<span class="op">(</span><span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb46-11"><a href="#cb46-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb46-12"><a href="#cb46-12" aria-hidden="true" tabindex="-1"></a>  <span class="co">// expected to return nullptr if the scope is closed</span></span>
<span id="cb46-13"><a href="#cb46-13" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(!</span>op<span class="op">)</span> <span class="op">{</span></span>
<span id="cb46-14"><a href="#cb46-14" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span>;</span>
<span id="cb46-15"><a href="#cb46-15" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-16"><a href="#cb46-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb46-17"><a href="#cb46-17" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb46-18"><a href="#cb46-18" aria-hidden="true" tabindex="-1"></a>    <span class="kw">new</span> <span class="op">((</span><span class="dt">void</span><span class="op">)</span>op<span class="op">)</span> op_t<span class="op">{</span></span>
<span id="cb46-19"><a href="#cb46-19" aria-hidden="true" tabindex="-1"></a>        <span class="fu">connect</span><span class="op">(</span>forward<span class="op">&lt;</span>Sender<span class="op">&gt;(</span>sndr<span class="op">)</span>, spawn_receiver<span class="op">{</span>op, alloc, env<span class="op">})}</span>;</span>
<span id="cb46-20"><a href="#cb46-20" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-21"><a href="#cb46-21" aria-hidden="true" tabindex="-1"></a>  <span class="cf">catch</span> <span class="op">(...)</span> <span class="op">{</span></span>
<span id="cb46-22"><a href="#cb46-22" aria-hidden="true" tabindex="-1"></a>    alloc<span class="op">.</span>deallocate<span class="op">(</span>op, <span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb46-23"><a href="#cb46-23" aria-hidden="true" tabindex="-1"></a>    <span class="cf">throw</span>;</span>
<span id="cb46-24"><a href="#cb46-24" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-25"><a href="#cb46-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb46-26"><a href="#cb46-26" aria-hidden="true" tabindex="-1"></a>  op<span class="op">-&gt;</span>start<span class="op">()</span>;</span>
<span id="cb46-27"><a href="#cb46-27" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Since <code class="sourceCode default">spawn()</code> makes the
allocator it used available to the spawned work by putting it in the
<code class="sourceCode default">spawn-receiver</code>’s environment, a
side effect of this choice is that all allocations that happen inside
the spawned work through the wrapped allocator would be manipulating the
scope’s refcount.</p>
<h1 data-number="7" id="naming"><span class="header-section-number">7</span> Naming<a href="#naming" class="self-link"></a></h1>
<p>As is often true, naming is a difficult task. We feel more confident
about having arrived at a reasonably good naming <em>scheme</em> than
good <em>names</em>:</p>
<ul>
<li><p>There is some consensus that the default standard “scope” should
be the one this paper calls
<code class="sourceCode default">counting_scope</code> because it
provides all of the obviously-useful features of a scope, while
<code class="sourceCode default">simple_counting_scope</code> is the
more spare type that only provides scoping facilities. Therefore,
<code class="sourceCode default">counting_scope</code> should get the
“nice” name, while
<code class="sourceCode default">simple_counting_scope</code> should get
a more cumbersome name that conveys fewer features in exchange for a
smaller object size and fewer atomic operations.</p></li>
<li><p>Most people seem to hate the name
<code class="sourceCode default">counting_scope</code> because the
“counting” is an implementation detail, there are arguments about
whether it’s really “scoping” anything, and the name doesn’t really tell
you what the type is <em>for</em>. The leading suggestion for a better
name is to pick one that conveys that the type “groups together” or
“keeps track of” “tasks”, “senders”, or “operations”. Examples of this
scheme include <code class="sourceCode default">task_pool</code>,
<code class="sourceCode default">sender_group</code>, and
<code class="sourceCode default">task_arena</code>. We like the
suggested pattern but seek LEWG’s feedback on:</p>
<ul>
<li>Should we choose <code class="sourceCode default">task</code> or
<code class="sourceCode default">sender</code> to desribe the thing
being “grouped”? <code class="sourceCode default">task</code> feels
friendlier, but might risk conveying that not all sender types are
supported.</li>
<li>What word should we use to describe the “grouping”?
<ul>
<li><code class="sourceCode default">pool</code> often means a
pre-allocated group of resources that can be borrowed from and returned
to, which isn’t appropriate.</li>
<li><code class="sourceCode default">group</code> is either the most
generic word for a group of things, or an unrelated mathematical
object.</li>
<li><code class="sourceCode default">arena</code> is used outside
computing to mean a place where competitions happen, and within
computing to refer to a memory allocation strategy.</li>
<li>Something else?</li>
</ul></li>
</ul></li>
<li><p>The name-part <code class="sourceCode default">token</code> was
selected by analogy to
<code class="sourceCode default">stop_token</code>, but it feels like a
loose analogy. Perhaps <code class="sourceCode default">handle</code> or
<code class="sourceCode default">ref</code> (short for
<code class="sourceCode default">reference</code>) would be better.
<code class="sourceCode default">ref</code> is nice for being short and
accurate.</p></li>
<li><p>The likely use of the
<code class="sourceCode default">async_scope_token</code> concept will
be to constrain algorithms that accept a sender and a token with code
like the following:</p>
<div class="sourceCode" id="cb47"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb47-1"><a href="#cb47-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, async_scope_token<span class="op">&lt;</span>Sender<span class="op">&gt;</span> Token<span class="op">&gt;</span></span>
<span id="cb47-2"><a href="#cb47-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">(</span>Sender, Token<span class="op">)</span>;</span></code></pre></div>
<p>Perhaps the concept name should end in
<code class="sourceCode default">_for</code> so that the above code
would read</p>
<div class="sourceCode" id="cb48"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb48-1"><a href="#cb48-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, async_scope_token_for<span class="op">&lt;</span>Sender<span class="op">&gt;</span> Token<span class="op">&gt;</span></span>
<span id="cb48-2"><a href="#cb48-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">(</span>Sender, Token<span class="op">)</span>;</span></code></pre></div>
<p>We propose the token concept should be named
<code class="sourceCode default">async_</code> <code class="sourceCode default">&lt;new name of counting_scope&gt;</code>
<code class="sourceCode default">&lt;new word for token&gt;</code>
<code class="sourceCode default">_for</code>. Assuming we choose
<code class="sourceCode default">task_pool</code> and
<code class="sourceCode default">ref</code>, that would produce
<code class="sourceCode default">async_task_pool_ref_for</code>, which
would look like this:</p>
<div class="sourceCode" id="cb49"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb49-1"><a href="#cb49-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, async_task_pool_ref_for<span class="op">&lt;</span>Sender<span class="op">&gt;</span> Ref<span class="op">&gt;</span></span>
<span id="cb49-2"><a href="#cb49-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">(</span>Sender, Ref<span class="op">)</span>;</span></code></pre></div></li>
<li><p>The <code class="sourceCode default">simple</code> prefix does
not convey much about how
<code class="sourceCode default">simple_counting_scope</code> is
“simple”. Suggestions for alternatives include:</p>
<ul>
<li><code class="sourceCode default">fast</code> by analogy to the
<code class="sourceCode default">fast</code>-prefixed standard integer
types, which are so-named because they’re expected to be efficient.</li>
<li><code class="sourceCode default">non_cancellable</code> to speak to
what’s “missing” relative to
<code class="sourceCode default">counting_scope</code>, however,
<code class="sourceCode default">simple_counting_scope</code> does not
change the cancellability of senders nested within it and we worry that
this suggestion might convey that senders nested within a
<code class="sourceCode default">non_cancellable</code> scope might
somehow <em>lose</em> cancellability.</li>
</ul></li>
</ul>
<h2 data-number="7.1" id="nest"><span class="header-section-number">7.1</span>
<code class="sourceCode default">nest()</code><a href="#nest" class="self-link"></a></h2>
<p>This provides a way to build a sender that is associated with a
“scope”, which is a type that implements and enforces some bookkeeping
policy regarding the senders nested within it.
<code class="sourceCode default">nest()</code> does not allocate state,
call connect, or call start.
<code class="sourceCode default">nest()</code> is the basis operation
for async scopes. <code class="sourceCode default">spawn()</code> and
<code class="sourceCode default">spawn_future()</code> use
<code class="sourceCode default">nest()</code> to associate a given
sender with a given scope, and then they allocate, connect, and start
the resulting sender.</p>
<p>It would be good for the name to indicate that it is a simple
operation (insert, add, embed, extend might communicate allocation,
which <code class="sourceCode default">nest()</code> does not do).</p>
<p>alternatives: <code class="sourceCode default">wrap()</code>,
<code class="sourceCode default">attach()</code>,
<code class="sourceCode default">track()</code>,
<code class="sourceCode default">add()</code>,
<code class="sourceCode default">associate()</code></p>
<h2 data-number="7.2" id="async_scope_token"><span class="header-section-number">7.2</span>
<code class="sourceCode default">async_scope_token</code><a href="#async_scope_token" class="self-link"></a></h2>
<p>This is a concept that is satisfied by types that support nesting
senders within themselves. It is primarily useful for constraining the
arguments to <code class="sourceCode default">spawn()</code> and
<code class="sourceCode default">spawn_future()</code> to give useful
error messages for invalid invocations.</p>
<p>Since concepts don’t support existential quantifiers and thus can’t
express “type <code class="sourceCode default">T</code> is an
<code class="sourceCode default">async_scope_token</code> if there
exists a sender, <code class="sourceCode default">s</code>, for which
<code class="sourceCode default">t.nest(s)</code> is valid”, the
<code class="sourceCode default">async_scope_token</code> concept must
be parameterized on both the type of the token and the type of some
particular sender and thus describes whether <em>this</em> token type is
an <code class="sourceCode default">async_scope_token</code> in
combination with <em>this</em> sender type. Given this limitation,
perhaps the name should convey something about the fact that it is
checking the relationship between two types rather than checking
something about the scope’s type alone. Nothing satisfying comes to
mind.</p>
<p>alternatives: <code class="sourceCode default">task_pool_ref</code>,
<code class="sourceCode default">task_pool_token</code>,
<code class="sourceCode default">task_group_ref</code>,
<code class="sourceCode default">sender_group_ref</code>,
<code class="sourceCode default">task_group_token</code>,
<code class="sourceCode default">sender_group_token</code>, don’t name
it and leave it as
<em><code class="sourceCode default">exposition-only</code></em></p>
<h2 data-number="7.3" id="spawn"><span class="header-section-number">7.3</span>
<code class="sourceCode default">spawn()</code><a href="#spawn" class="self-link"></a></h2>
<p>This provides a way to start a sender that produces
<code class="sourceCode default">void</code> and to associate the
resulting async work with an async scope that can implement a
bookkeeping policy that may help ensure the async work is complete
before destroying any resources it is using. This allocates, connects,
and starts the given sender.</p>
<p>It would be good for the name to indicate that it is an expensive
operation.</p>
<p>alternatives:
<code class="sourceCode default">connect_and_start()</code>,
<code class="sourceCode default">spawn_detached()</code>,
<code class="sourceCode default">fire_and_remember()</code></p>
<h2 data-number="7.4" id="spawn_future"><span class="header-section-number">7.4</span>
<code class="sourceCode default">spawn_future()</code><a href="#spawn_future" class="self-link"></a></h2>
<p>This provides a way to start work and later ask for the result. This
will allocate, connect, and start the given sender, while resolving the
race (using synchronization primitives) between the completion of the
given sender and the start of the returned sender. Since the type of the
receiver supplied to the result sender is not known when the given
sender starts, the receiver will be type-erased when it is
connected.</p>
<p>It would be good for the name to be ugly, to indicate that it is a
more expensive operation than
<code class="sourceCode default">spawn()</code>.</p>
<p>alternatives:
<code class="sourceCode default">spawn_with_result()</code></p>
<h2 data-number="7.5" id="simple_counting_scope"><span class="header-section-number">7.5</span>
<code class="sourceCode default">simple_counting_scope</code><a href="#simple_counting_scope" class="self-link"></a></h2>
<p>A <code class="sourceCode default">simple_counting_scope</code>
represents the root of a set of nested lifetimes.</p>
<p>One mental model for this is a semaphore. It tracks a count of
lifetimes and fires an event when the count reaches 0.</p>
<p>Another mental model for this is block syntax.
<code class="sourceCode default">{}</code> represents the root of a set
of lifetimes of locals and temporaries and nested blocks.</p>
<p>Another mental model for this is a container. This is the least
accurate model. This container is a value that does not contain values.
This container contains a set of active senders (an active sender is not
a value, it is an operation).</p>
<p>alternatives:
<code class="sourceCode default">simple_async_scope</code>,
<code class="sourceCode default">simple_task_pool</code>,
<code class="sourceCode default">fast_task_pool</code>,
<code class="sourceCode default">non_cancellable_task_pool</code>,
<code class="sourceCode default">simple_task_group</code>,
<code class="sourceCode default">simple_sender_group</code></p>
<h2 data-number="7.6" id="counting_scope-1"><span class="header-section-number">7.6</span>
<code class="sourceCode default">counting_scope</code><a href="#counting_scope-1" class="self-link"></a></h2>
<p>Has all of the same behavior as
<code class="sourceCode default">simple_counting_scope</code>, with the
added functionality of cancellation; work
<code class="sourceCode default">nest</code>-ed on this scope can be
asked to cancel <em>en masse</em> from the scope.</p>
<p>alternatives: <code class="sourceCode default">async_scope</code>,
<code class="sourceCode default">task_pool</code>,
<code class="sourceCode default">task_group</code>,
<code class="sourceCode default">sender_group</code></p>
<h3 data-number="7.6.1" id="counting_scopejoin-1"><span class="header-section-number">7.6.1</span>
<code class="sourceCode default">counting_scope::join()</code><a href="#counting_scopejoin-1" class="self-link"></a></h3>
<p>This method returns a sender that, when started, prevents new senders
from being nested within the scope and then waits for the scope’s count
of outstanding senders to drop to zero before completing. It is somewhat
analogous to <code class="sourceCode default">std::thread::join()</code>
but does not block.</p>
<p><code class="sourceCode default">join()</code> must be invoked, and
the returned sender must be connected, started, and completed, before
the scope may be destroyed so it may be useful to convey some of this
importance in the name, although
<code class="sourceCode default">std::thread</code> has similar
requirements for its <code class="sourceCode default">join()</code>.</p>
<p><code class="sourceCode default">join()</code> is the biggest wart in
this design; the need to manually manage the end of a scope’s lifetime
stands out as less-than-ideal in C++, and there is some real risk that
users will write deadlocks with
<code class="sourceCode default">join()</code> so perhaps
<code class="sourceCode default">join()</code> should have a name that
conveys danger.</p>
<p>alternatives: <code class="sourceCode default">complete()</code>,
<code class="sourceCode default">close()</code></p>
<h1 data-number="8" id="specification"><span class="header-section-number">8</span> Specification<a href="#specification" class="self-link"></a></h1>
<h2 data-number="8.1" id="executionasync_scope_token-1"><span class="header-section-number">8.1</span>
<code class="sourceCode default">execution::async_scope_token</code><a href="#executionasync_scope_token-1" class="self-link"></a></h2>
<p>Add the following as a new subsection immediately after
<strong>[exec.utils.tfxcmplsigs]</strong>:</p>
<div class="add" style="color: #006e28">
<p><strong><code class="sourceCode default">std::execution::async_scope_token</code>
[exec.asyncscopetoken.concept]</strong></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The <code class="sourceCode default">async_scope_token&lt;Token, Sndr&gt;</code>
concept defines the requirements on an object of type
<code class="sourceCode default">Token</code> that can be used to
associate a sender of type <code class="sourceCode default">Sndr</code>
with the token’s associated async scope object.</p>
<div class="sourceCode" id="cb50"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb50-1"><a href="#cb50-1" aria-hidden="true" tabindex="-1"></a>namespace std::execution {</span>
<span id="cb50-2"><a href="#cb50-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-3"><a href="#cb50-3" aria-hidden="true" tabindex="-1"></a>template &lt;class Token, class Sender&gt;</span>
<span id="cb50-4"><a href="#cb50-4" aria-hidden="true" tabindex="-1"></a>concept async_scope_token =</span>
<span id="cb50-5"><a href="#cb50-5" aria-hidden="true" tabindex="-1"></a>    sender&lt;Sender&gt; &amp;&amp;</span>
<span id="cb50-6"><a href="#cb50-6" aria-hidden="true" tabindex="-1"></a>    requires(Token token, Sender&amp;&amp; snd) {</span>
<span id="cb50-7"><a href="#cb50-7" aria-hidden="true" tabindex="-1"></a>      { token.nest(std::forward&lt;Sender&gt;(snd)) } -&gt; sender;</span>
<span id="cb50-8"><a href="#cb50-8" aria-hidden="true" tabindex="-1"></a>    } &amp;&amp;</span>
<span id="cb50-9"><a href="#cb50-9" aria-hidden="true" tabindex="-1"></a>    copyable&lt;Token&gt;;</span>
<span id="cb50-10"><a href="#cb50-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-11"><a href="#cb50-11" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<code class="sourceCode default">async_scope_token&lt;Token, Sndr&gt;</code>
is modeled only if <code class="sourceCode default">Token</code>’s copy
and move operations are not potentially throwing.</p>
</div>
<h2 data-number="8.2" id="executionnest-1"><span class="header-section-number">8.2</span>
<code class="sourceCode default">execution::nest</code><a href="#executionnest-1" class="self-link"></a></h2>
<p>Add the following as a new subsection immediately after
<strong>[exec.stopped.as.error]</strong>:</p>
<div class="add" style="color: #006e28">
<p><strong><code class="sourceCode default">std::execution::nest</code>
[exec.nest]</strong></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<code class="sourceCode default">nest</code> tries to associate a sender
with an async scope such that the scope can track the lifetime of any
async operations created with the sender.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
The name <code class="sourceCode default">nest</code> denotes a
customization point object. For subexpressions
<code class="sourceCode default">sndr</code> and
<code class="sourceCode default">token</code>, let
<code class="sourceCode default">Sndr</code> be
<code class="sourceCode default">decltype((sndr))</code> and let
<code class="sourceCode default">Token</code> be
<code class="sourceCode default">decltype((token))</code>. If <code class="sourceCode default">async_scope_token&lt;Sender, Token&gt;</code>
is false, the expression
<code class="sourceCode default">nest(sndr, token)</code> is
ill-formed.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
Otherwise, the expression
<code class="sourceCode default">nest(sndr, token)</code> is
expression-equivalent to:</p>
<div class="sourceCode" id="cb51"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb51-1"><a href="#cb51-1" aria-hidden="true" tabindex="-1"></a>auto(token).nest(sndr);</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
The evaluation of
<code class="sourceCode default">nest(sndr, token)</code> may cause side
effects observable via <code class="sourceCode default">token</code>’s
associated async scope object.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
Let the subexpression <code class="sourceCode default">out_sndr</code>
denote the result of the invocation
<code class="sourceCode default">nest(sndr, token)</code> or an object
copied or moved from such, and let the subexpression
<code class="sourceCode default">rcvr</code> denote a receiver such that
the expression
<code class="sourceCode default">connect(out_sndr, rcvr)</code> is
well-formed. The expression
<code class="sourceCode default">connect(out_sndr, rcvr)</code> has
undefined behavior unless it creates an asynchronous operation
(<strong>[async.ops]</strong>) that, when started:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span>
TODO: specify that starting
<code class="sourceCode default">out_sndr</code> starts
<code class="sourceCode default">sndr</code> unless
<code class="sourceCode default">out_sndr</code> is an unassociated
sender.</li>
</ul>

</div>
<h2 data-number="8.3" id="executionspawn-1"><span class="header-section-number">8.3</span>
<code class="sourceCode default">execution::spawn</code><a href="#executionspawn-1" class="self-link"></a></h2>
<p>spec here</p>
<h2 data-number="8.4" id="executionspawn_future-1"><span class="header-section-number">8.4</span>
<code class="sourceCode default">execution::spawn_future</code><a href="#executionspawn_future-1" class="self-link"></a></h2>
<p>spec here</p>
<h2 data-number="8.5" id="executionsimple_counting_scope-1"><span class="header-section-number">8.5</span>
<code class="sourceCode default">execution::simple_counting_scope</code><a href="#executionsimple_counting_scope-1" class="self-link"></a></h2>
<p>spec here</p>
<h2 data-number="8.6" id="executioncounting_scope-1"><span class="header-section-number">8.6</span>
<code class="sourceCode default">execution::counting_scope</code><a href="#executioncounting_scope-1" class="self-link"></a></h2>
<p>spec here</p>
<h1 data-number="9" id="acknowledgements"><span class="header-section-number">9</span> Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<p>Thanks to Andrew Royes for unwavering support for the development and
deployment of Unifex at Meta and for recognizing the importance of
contributing this paper to the C++ Standard.</p>
<p>Thanks to Eric Niebler for the encouragement and support it took to
get this paper published.</p>
<h1 data-number="10" id="bibliography"><span class="header-section-number">10</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" role="doc-bibliography">
<div id="ref-Dahl72" class="csl-entry" role="doc-biblioentry">
[Dahl72] O.-J. Dahl, E. W. Dijkstra, and C. A. R. Hoare. <em>Structured
Programming</em>. Academic Press Ltd., 1972.
</div>
<div id="ref-follycoro" class="csl-entry" role="doc-biblioentry">
[<code class="sourceCode default">folly::coro</code>] folly::coro. <a href="https://github.com/facebook/folly/tree/main/folly/experimental/coro"><div class="csl-block">https://github.com/facebook/folly/tree/main/folly/experimental/coro</div></a>
</div>
<div id="ref-follyasyncscope" class="csl-entry" role="doc-biblioentry">
[<code class="sourceCode default">folly::coro::AsyncScope</code>]
folly::coro::AsyncScope. <a href="https://github.com/facebook/folly/blob/main/folly/experimental/coro/AsyncScope.h"><div class="csl-block">https://github.com/facebook/folly/blob/main/folly/experimental/coro/AsyncScope.h</div></a>
</div>
<div id="ref-iouringserver" class="csl-entry" role="doc-biblioentry">
[io_uring HTTP server] io_uring HTTP server. <a href="https://github.com/facebookexperimental/libunifex/blob/main/examples/linux/http_server_io_uring_test.cpp"><div class="csl-block">https://github.com/facebookexperimental/libunifex/blob/main/examples/linux/http_server_io_uring_test.cpp</div></a>
</div>
<div id="ref-libunifex" class="csl-entry" role="doc-biblioentry">
[libunifex] libunifex. <a href="https://github.com/facebookexperimental/libunifex/"><div class="csl-block">https://github.com/facebookexperimental/libunifex/</div></a>
</div>
<div id="ref-P2079R2" class="csl-entry" role="doc-biblioentry">
[P2079R2] Lee Howes, Ruslan Arutyunyan, Michael Voss. 2022-01-15. System
execution context. <a href="https://wg21.link/p2079r2"><div class="csl-block">https://wg21.link/p2079r2</div></a>
</div>
<div id="ref-P2300R7" class="csl-entry" role="doc-biblioentry">
[P2300R7] Eric Niebler, Michał Dominiak, Georgy Evtushenko, Lewis Baker,
Lucian Radu Teodorescu, Lee Howes, Kirk Shoop, Michael Garland, Bryce
Adelstein Lelbach. 2023-04-21. `std::execution`. <a href="https://wg21.link/p2300r7"><div class="csl-block">https://wg21.link/p2300r7</div></a>
</div>
<div id="ref-P3296R0" class="csl-entry" role="doc-biblioentry">
[P3296R0] Anthony Williams. let_async_scope. <a href="https://wg21.link/p3296r0"><div class="csl-block">https://wg21.link/p3296r0</div></a>
</div>
<div id="ref-rsys" class="csl-entry" role="doc-biblioentry">
[rsys] A smaller, faster video calling library for our apps. <a href="https://engineering.fb.com/2020/12/21/video-engineering/rsys/"><div class="csl-block">https://engineering.fb.com/2020/12/21/video-engineering/rsys/</div></a>
</div>
<div id="ref-asyncscopeunifexv1" class="csl-entry" role="doc-biblioentry">
[<code class="sourceCode default">unifex::v1::async_scope</code>]
unifex::v1::async_scope. <a href="https://github.com/facebookexperimental/libunifex/blob/main/include/unifex/v1/async_scope.hpp"><div class="csl-block">https://github.com/facebookexperimental/libunifex/blob/main/include/unifex/v1/async_scope.hpp</div></a>
</div>
<div id="ref-asyncscopeunifexv2" class="csl-entry" role="doc-biblioentry">
[<code class="sourceCode default">unifex::v2::async_scope</code>]
unifex::v2::async_scope. <a href="https://github.com/facebookexperimental/libunifex/blob/main/include/unifex/v2/async_scope.hpp"><div class="csl-block">https://github.com/facebookexperimental/libunifex/blob/main/include/unifex/v2/async_scope.hpp</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
