<!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="2025-02-18" />
  <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>P3149R9</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2025-02-18</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@gmail.com" class="email">ispeters@gmail.com</a>&gt;<br>
      Jessica Wong<br>&lt;<a href="mailto:jesswong2011@gmail.com" class="email">jesswong2011@gmail.com</a>&gt;<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Contributors:</td>
    <td>
      Dietmar Kühl<br>&lt;<a href="mailto:dkuhl@bloomberg.net" class="email">dkuhl@bloomberg.net</a>&gt;<br>
      Ján Ondrušek<br>&lt;<a href="mailto:ondrusek@meta.com" class="email">ondrusek@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>
      Ruslan Arutyunyan<br>&lt;<a href="mailto:ruslan.arutyunyan@intel.com" class="email">ruslan.arutyunyan@intel.com</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="#r9" id="toc-r9"><span class="toc-section-number">1.1</span> R9<span></span></a></li>
<li><a href="#r8" id="toc-r8"><span class="toc-section-number">1.2</span> R8<span></span></a></li>
<li><a href="#r7" id="toc-r7"><span class="toc-section-number">1.3</span> R7<span></span></a></li>
<li><a href="#r6" id="toc-r6"><span class="toc-section-number">1.4</span> R6<span></span></a>
<ul>
<li><a href="#the-problem" id="toc-the-problem"><span class="toc-section-number">1.4.1</span> The
Problem<span></span></a></li>
<li><a href="#some-solutions" id="toc-some-solutions"><span class="toc-section-number">1.4.2</span> Some
Solutions<span></span></a></li>
<li><a href="#lewg-discussion-in-st-louis" id="toc-lewg-discussion-in-st-louis"><span class="toc-section-number">1.4.3</span> LEWG Discussion in St
Louis<span></span></a></li>
</ul></li>
<li><a href="#r5" id="toc-r5"><span class="toc-section-number">1.5</span> R5<span></span></a></li>
<li><a href="#r4" id="toc-r4"><span class="toc-section-number">1.6</span> R4<span></span></a></li>
<li><a href="#r3" id="toc-r3"><span class="toc-section-number">1.7</span> R3<span></span></a></li>
<li><a href="#r2" id="toc-r2"><span class="toc-section-number">1.8</span> R2<span></span></a></li>
<li><a href="#r1" id="toc-r1"><span class="toc-section-number">1.9</span> R1<span></span></a></li>
<li><a href="#r0" id="toc-r0"><span class="toc-section-number">1.10</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_async_scope-are-a-step-forward-towards-structured-concurrency" id="toc-counting_scope-and-let_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_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_async_scope-with-spawn" id="toc-let_async_scope-with-spawn"><span class="toc-section-number">4.6.1</span>
<code class="sourceCode default">let_async_scope</code> with
<code class="sourceCode default">spawn()</code><span></span></a></li>
<li><a href="#let_async_scope-with-spawn_future" id="toc-let_async_scope-with-spawn_future"><span class="toc-section-number">4.6.2</span>
<code class="sourceCode default">let_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_scopetokenwrap" id="toc-simple_counting_scopetokenwrap"><span class="toc-section-number">5.6.6</span> <code class="sourceCode default">simple_counting_scope::token::wrap</code><span></span></a></li>
<li><a href="#simple_counting_scopetokentry_associate" id="toc-simple_counting_scopetokentry_associate"><span class="toc-section-number">5.6.7</span> <code class="sourceCode default">simple_counting_scope::token::try_associate</code><span></span></a></li>
<li><a href="#simple_counting_scopetokendisassociate" id="toc-simple_counting_scopetokendisassociate"><span class="toc-section-number">5.6.8</span> <code class="sourceCode default">simple_counting_scope::token::disassociate</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_scopetokenwrap" id="toc-counting_scopetokenwrap"><span class="toc-section-number">5.7.7</span>
<code class="sourceCode default">counting_scope::token::wrap</code><span></span></a></li>
<li><a href="#counting_scopetokentry_associate" id="toc-counting_scopetokentry_associate"><span class="toc-section-number">5.7.8</span> <code class="sourceCode default">counting_scope::token::try_associate</code><span></span></a></li>
</ul></li>
<li><a href="#when-to-use-counting_scope-vs-p3296r2s-let_async_scope" id="toc-when-to-use-counting_scope-vs-p3296r2s-let_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="P3296R2">[<span>P3296R2</span>]</span>’s
<code class="sourceCode default">let_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>
</ul></li>
<li><a href="#naming" id="toc-naming"><span class="toc-section-number">7</span> Naming<span></span></a>
<ul>
<li><a href="#async_scope_token" id="toc-async_scope_token"><span class="toc-section-number">7.1</span>
<code class="sourceCode default">async_scope_token</code><span></span></a></li>
<li><a href="#nest" id="toc-nest"><span class="toc-section-number">7.2</span>
<code class="sourceCode default">nest()</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="#header-version-synopsis-version.syn" id="toc-header-version-synopsis-version.syn"><span class="toc-section-number">8.1</span> Header
<code class="sourceCode default">&lt;version&gt;</code> synopsis
<span>17.3.2
<span>[version.syn]</span></span><span></span></a></li>
<li><a href="#header-execution-synopsis-execution.syn" id="toc-header-execution-synopsis-execution.syn"><span class="toc-section-number">8.2</span> Header
<code class="sourceCode default">&lt;execution&gt;</code> synopsis
<span>33.4
<span>[execution.syn]</span></span><span></span></a></li>
<li><a href="#executionnest-1" id="toc-executionnest-1"><span class="toc-section-number">8.3</span>
<code class="sourceCode default">execution::nest</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="#executionspawn-1" id="toc-executionspawn-1"><span class="toc-section-number">8.5</span>
<code class="sourceCode default">execution::spawn</code><span></span></a></li>
<li><a href="#async-scope-utilities" id="toc-async-scope-utilities"><span class="toc-section-number">8.6</span> Async scope
utilities<span></span></a></li>
<li><a href="#async-scope-concepts" id="toc-async-scope-concepts"><span class="toc-section-number">8.7</span> Async scope
concepts<span></span></a></li>
<li><a href="#executionsimple_counting_scope-and-executioncounting_scope" id="toc-executionsimple_counting_scope-and-executioncounting_scope"><span class="toc-section-number">8.8</span>
<code class="sourceCode default">execution::simple_counting_scope</code>
and
<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="r9"><span class="header-section-number">1.1</span> R9<a href="#r9" class="self-link"></a></h2>
<ul>
<li><p>Apply feedback received from LWG during the Hagenberg
meeting.</p></li>
<li><p>Update the language used in
<code class="sourceCode default">simple_counting_scope::join</code> and
<code class="sourceCode default">counting_scope::join</code> to
explicitly specify the behavior of completion as captured in the
following polls taken by LEWG:</p>
<p>POLL: We would like to explicitly specify the behaviour of the
completion of join (by possibly doing: if conditions are met either
complete synchronously inside start or completing asynchronously by
explicitly creating a scheduler, join operation should never be
completed by scheduling).</p>
<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;">4</td>
<td style="text-align: right;">5</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
</tr>
</tbody>
</table>
<p>Attendance: 20 (IP) + 7 (R)</p>
<p>Author’s Position: SF</p>
<p>Outcome: Consensus in favor</p>
<p>POLL: When the operation completes immediately, schedule instead of
completing inline.</p>
<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;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">8</td>
<td style="text-align: right;">3</td>
</tr>
</tbody>
</table>
<p>Attendance: 20 (IP) + 7 (R)</p>
<p>Author’s Position: A</p>
<p>Outcome: Strong consensus against</p>
<p>POLL: When the operation completes asynchronously, complete inline
instead of scheduling.</p>
<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;">1</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">7</td>
<td style="text-align: right;">0</td>
</tr>
</tbody>
</table>
<p>Attendance: 20 (IP) + 7 (R)</p>
<p>Author’s Position: A</p>
<p>Outcome: Consensus against.</p></li>
<li><p>Update wording to reflect LEWG requested changes before
forwarding to LWG for review as captured in the poll below:</p>
<p>POLL: Apply the changes and fixes above on async_scope, and forward
the fixed version P3149R9 to LWG for C++26.</p>
<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;">7</td>
<td style="text-align: right;">5</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
</tr>
</tbody>
</table>
<p>Attendance: X (IP) + X (R)</p>
<p>Author’s Position: SF</p>
<p>Outcome: Consensus in favor</p></li>
</ul>
<h2 data-number="1.2" id="r8"><span class="header-section-number">1.2</span> R8<a href="#r8" class="self-link"></a></h2>
<ul>
<li><p>Replace
<code class="sourceCode default">~async_scope_association()</code> with
<code class="sourceCode default">async_scope_token.disassociate()</code>
to address concerns raised during the LEWG meeting in Wrocław as
captured in the polls below. The primary concern was the non-regularity
of <code class="sourceCode default">async_scope_association</code>’s
unusual copy constructor; requiring Standard Library implementers to
remember to invoke
<code class="sourceCode default">scopeToken.disassociate()</code> rather
than relying on a non-regular RAII handle to do it automatically has
more consensus.</p>
<p>POLL: We would like to change the spelling of the copy constructor of
async_scope_association.</p>
<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;">5</td>
<td style="text-align: right;">7</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">15</td>
<td style="text-align: right;">2</td>
</tr>
</tbody>
</table>
<p>Attendance: [not recorded]</p>
<p># of Authors: 2</p>
<p>Authors’ position: 2x A</p>
<p>Outcome: No consensus for change</p>
<p>SF: We don’t have any copy ctor in the whole standard library that
fails by silently not performing a copy.</p>
<p>SA: If we’re not going to say this is a valid use of a copy ctor then
we’re saying this room doesn’t believe in RAII.</p>
<p>POLL: Modify the spelling of the copy constructor of
“async_scope_association” concept, without changing the copy constructor
of “nest”.</p>
<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;">1</td>
<td style="text-align: right;">6</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">2</td>
</tr>
</tbody>
</table>
<p>Attendance: 30 IP + 6 (19 IP)</p>
<p># of Authors: 2</p>
<p>Author’s Position: F + F</p>
<p>Outcome: Consensus in favor</p>
<p>SA: I was not permitted to ask questions about the poll</p></li>
<li><p>Update the words of power regarding how various parts of the
proposed types interact with the C++ memory model.</p></li>
</ul>
<h2 data-number="1.3" id="r7"><span class="header-section-number">1.3</span> R7<a href="#r7" class="self-link"></a></h2>
<ul>
<li>Add wording to section 8.</li>
<li>Remove the allocator from the environment in
<code class="sourceCode default">spawn</code> and
<code class="sourceCode default">spawn_future</code> when the allocator
selection algorithm falls all the way back to using
<code class="sourceCode default">std::allocator&lt;&gt;</code> because
there’s no other choice.</li>
<li>Fix the last two typos in the example code.</li>
<li>Small changes to how <code class="sourceCode default">spawn</code>
and <code class="sourceCode default">spawn_future</code> set up the
environment for the spawned operation based on feedback from Dietmar and
Ruslan.</li>
</ul>
<h2 data-number="1.4" id="r6"><span class="header-section-number">1.4</span> R6<a href="#r6" class="self-link"></a></h2>
<p>In revision 4 of this paper, 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> (and
<code class="sourceCode default">spawn_future()</code>) when the
<code class="sourceCode default">counting_scope</code> that tracks the
spawned work is being used to protect against out-of-lifetime accesses
to the allocator provided to
<code class="sourceCode default">spawn()</code>. Revision 5 of this
paper raised Lewis’s concerns and presented several solutions. Revision
6 has selected the solution originally presented as “option 4”: 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.</p>
<h3 data-number="1.4.1" id="the-problem"><span class="header-section-number">1.4.1</span> The Problem<a href="#the-problem" class="self-link"></a></h3>
<p>What follows is a description, taken from revision 5, section 6.5.1,
of the problem with using <code class="sourceCode default">nest()</code>
as the basis operation for implementing
<code class="sourceCode default">spawn()</code> (a similar problem
exists for <code class="sourceCode default">spawn_future()</code> but
<code class="sourceCode default">spawn()</code> is simpler to
explain).</p>
<p>When a spawned operation completes, the order of operations was 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="1.4.2" id="some-solutions"><span class="header-section-number">1.4.2</span> Some Solutions<a href="#some-solutions" class="self-link"></a></h3>
<p>Revision 5 presented the following possible solutions:</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 decrement 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>
<h3 data-number="1.4.3" id="lewg-discussion-in-st-louis"><span class="header-section-number">1.4.3</span> LEWG Discussion in St Louis<a href="#lewg-discussion-in-st-louis" class="self-link"></a></h3>
<p>The authors opened the discussion by recommending option 6. By the
end of the discussion, the authors’ expressed preferences were: “4 &amp;
6 are better than 5; 5 is better than 3.” The biggest concern with
option 4 was the time required to rework the paper in terms of the new
basis operation.</p>
<p>The room took the following two straw polls:</p>
<ol type="1">
<li><p>In P3149R5 strike option 1 from 6.5.2 (option 1 would put the
responsibility to coordinate the lifetime of the memory resource on the
end user)</p>
<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;">2</td>
<td style="text-align: right;">3</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">1</td>
</tr>
</tbody>
</table>
<p>Attendance: 21 in-person + 10 remote</p>
<p># of Authors: 2</p>
<p>Authors’ position: 2x SF</p>
<p>Outcome: Consensus in favor</p>
<p>SA: I’m SA because I don’t think async scope needs to protect memory
allocations or resources, it’s fine for this not to be a capability and
I think adding this capability will add complexity, and that’ll mean it
doesn’t make C++26.</p></li>
<li><p>In P3149R5 strike option 2 from 6.5.2 (option 2 would prevent
spawn from supporting allocators)</p>
<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;">8</td>
<td style="text-align: right;">4</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">0</td>
</tr>
</tbody>
</table>
<p>Attendance: 21 in-person + 10 remote</p>
<p># of Authors: 2</p>
<p>Authors’ position: 2x SF</p>
<p>Outcome: Consensus in favor</p>
<p>WA: As someone who was weakly against I’m not ready to rule out this
possibility yet.</p></li>
</ol>
<p>Ultimately, the authors chose option 4, leading to revision 6 of the
paper changing from this:</p>
<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="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="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> async_scope_token <span class="op">=</span></span>
<span id="cb1-3"><a href="#cb1-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="cb1-4"><a href="#cb1-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="cb1-5"><a href="#cb1-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="cb1-6"><a href="#cb1-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="cb1-7"><a href="#cb1-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="cb1-8"><a href="#cb1-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="cb1-9"><a href="#cb1-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="cb1-10"><a href="#cb1-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="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span></code></pre></div>
<p>with <code class="sourceCode default">execution::nest()</code>
forwarding to the <code class="sourceCode default">nest()</code> method
on the provided token and
<code class="sourceCode default">spawn()</code> and
<code class="sourceCode default">spawn_future()</code> being expressed
in terms of <code class="sourceCode default">nest()</code>, to this:</p>
<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="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Assoc<span class="op">&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> async_scope_association <span class="op">=</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    semiregular<span class="op">&lt;</span>Assoc<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span><span class="op">(</span><span class="kw">const</span> Assoc<span class="op">&amp;</span> assoc<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;(</span>assoc<span class="op">)</span> <span class="op">}</span> <span class="kw">noexcept</span>;</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Token<span class="op">&gt;</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> async_scope_token <span class="op">=</span></span>
<span id="cb2-10"><a href="#cb2-10" 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="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span><span class="op">(</span>Token token<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span> token<span class="op">.</span>try_associate<span class="op">()</span> <span class="op">}</span> <span class="op">-&gt;</span> async_scope_association;</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span></code></pre></div>
<p>with <code class="sourceCode default">nest()</code>,
<code class="sourceCode default">spawn()</code>, and
<code class="sourceCode default">spawn_future()</code> all being
expressed in terms of the
<code class="sourceCode default">async_scope_token</code> concept.</p>
<h2 data-number="1.5" id="r5"><span class="header-section-number">1.5</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.6" id="r4"><span class="header-section-number">1.6</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_async_scope</code>.</li>
<li>Add some wording to a new <a href="#specification">Specification</a>
section</li>
</ul>
<h2 data-number="1.7" id="r3"><span class="header-section-number">1.7</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_async_scope</code> and
<code class="sourceCode default">counting_scope</code></li>
</ul>
<h2 data-number="1.8" id="r2"><span class="header-section-number">1.8</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.9" id="r1"><span class="header-section-number">1.9</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.10" id="r0"><span class="header-section-number">1.10</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="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="P3296R2">[<a href="#ref-P3296R2" role="doc-biblioref">P3296R2</a>]</span>: <code class="sourceCode cpp">sender <span class="kw">auto</span> let_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">class</span> simple_counting_scope</code>;
and</li>
<li><code class="sourceCode cpp"><span class="kw">class</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="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="co">// Abstraction for thread that has the ability</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="co">// to execute units of work.</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Executor <span class="op">{</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb3-5"><a href="#cb3-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="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><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="co">// Example class</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Foo <span class="op">{</span></span>
<span id="cb3-10"><a href="#cb3-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="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><span class="kw">public</span><span class="op">:</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> doSomething<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="kw">auto</span> asyncWork <span class="op">=</span> <span class="op">[&amp;]()</span> <span class="op">{</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>            <span class="co">// do something</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span>;</span>
<span id="cb3-17"><a href="#cb3-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="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="op">}</span>;</span></code></pre></div>

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

<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="co">// Utility class for executing async work on an</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="co">// async_scope and on the provided executor</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> ExecutorAsyncScopePair <span class="op">{</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    unifex<span class="op">::</span>v1<span class="op">::</span>async_scope scope_;</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    ExecutorScheduler exec_;</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb4-8"><a href="#cb4-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="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>        scope_<span class="op">.</span>detached_spawn_call_on<span class="op">(</span>exec_, func<span class="op">)</span>;</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> cleanup<span class="op">()</span> <span class="op">{</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> scope_<span class="op">.</span>cleanup<span class="op">()</span>;</span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a><span class="co">// Example class</span></span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Foo <span class="op">{</span></span>
<span id="cb4-19"><a href="#cb4-19" 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="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a>    <span class="op">~</span>Foo<span class="op">()</span> <span class="op">{</span></span>
<span id="cb4-23"><a href="#cb4-23" 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="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb4-25"><a href="#cb4-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-26"><a href="#cb4-26" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> doSomething<span class="op">()</span> <span class="op">{</span></span>
<span id="cb4-27"><a href="#cb4-27" 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="cb4-28"><a href="#cb4-28" aria-hidden="true" tabindex="-1"></a>            <span class="co">// do something</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>        exec_<span class="op">-&gt;</span>add<span class="op">(</span>asyncWork<span class="op">)</span>;</span>
<span id="cb4-32"><a href="#cb4-32" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb4-33"><a href="#cb4-33" 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="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>    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="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>        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="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a>    <span class="co">// `ctx` and `my_pool` are destroyed</span></span>
<span id="cb5-20"><a href="#cb5-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="P3296R2">[<a href="#ref-P3296R2" role="doc-biblioref">P3296R2</a>]</span>’s
<code class="sourceCode default">let_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="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> work_context;</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> work_item;</span>
<span id="cb6-5"><a href="#cb6-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="cb6-6"><a href="#cb6-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="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb6-9"><a href="#cb6-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="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>    work_context ctx;         <span class="co">// create a global context for the application</span></span>
<span id="cb6-11"><a href="#cb6-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="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a>    <span class="co">// make sure we always join</span></span>
<span id="cb6-14"><a href="#cb6-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="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a>        <span class="co">// wait for all nested work to finish</span></span>
<span id="cb6-16"><a href="#cb6-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="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-19"><a href="#cb6-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="cb6-20"><a href="#cb6-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="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a>        <span class="co">// Spawn some work dynamically</span></span>
<span id="cb6-22"><a href="#cb6-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="cb6-23"><a href="#cb6-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="cb6-24"><a href="#cb6-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-25"><a href="#cb6-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="cb6-26"><a href="#cb6-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="cb6-27"><a href="#cb6-27" aria-hidden="true" tabindex="-1"></a>        <span class="co">// and `ctx`)</span></span>
<span id="cb6-28"><a href="#cb6-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="cb6-29"><a href="#cb6-29" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb6-30"><a href="#cb6-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-31"><a href="#cb6-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="cb6-32"><a href="#cb6-32" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>With <span class="citation" data-cites="P3296R2">[<a href="#ref-P3296R2" role="doc-biblioref">P3296R2</a>]</span>’s
<code class="sourceCode default">let_async_scope</code>, one might write
safe code this way:</p>
<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> work_context;</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> work_item;</span>
<span id="cb7-5"><a href="#cb7-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="cb7-6"><a href="#cb7-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="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb7-9"><a href="#cb7-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="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>    work_context ctx; <span class="co">// create a global context for the application</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>    this_thread<span class="op">::</span>sync_wait<span class="op">(</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a>            ex<span class="op">::</span>let_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="kw">auto</span><span class="op">&amp;</span> items<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-14"><a href="#cb7-14" 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="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a>                    <span class="co">// Spawn some work dynamically</span></span>
<span id="cb7-16"><a href="#cb7-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>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="cb7-17"><a href="#cb7-17" 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="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">// start `snd` as before, but associate the spawned work with `scope` so that it</span></span>
<span id="cb7-20"><a href="#cb7-20" aria-hidden="true" tabindex="-1"></a>                    <span class="co">// can be awaited before destroying the resources referenced by the work (i.e.</span></span>
<span id="cb7-21"><a href="#cb7-21" aria-hidden="true" tabindex="-1"></a>                    <span class="co">// `my_pool` and `ctx`)</span></span>
<span id="cb7-22"><a href="#cb7-22" 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="cb7-23"><a href="#cb7-23" aria-hidden="true" tabindex="-1"></a>                <span class="op">}</span></span>
<span id="cb7-24"><a href="#cb7-24" aria-hidden="true" tabindex="-1"></a>                <span class="cf">return</span> just<span class="op">()</span>;</span>
<span id="cb7-25"><a href="#cb7-25" aria-hidden="true" tabindex="-1"></a>            <span class="op">}))</span>;</span>
<span id="cb7-26"><a href="#cb7-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-27"><a href="#cb7-27" 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="cb7-28"><a href="#cb7-28" 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_async_scope</code></strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<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></span>
<span id="cb8-9"><a href="#cb8-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="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>  <span class="co">// fire and forget</span></span>
<span id="cb8-12"><a href="#cb8-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="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a>  <span class="co">// `ctx` is destroyed, perhaps before</span></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a>  <span class="co">// `snd` is done</span></span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

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

<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="kw">struct</span> context;</span>
<span id="cb9-4"><a href="#cb9-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="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>  context ctx;</span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>  ex<span class="op">::</span>counting_scope scope;</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-10"><a href="#cb9-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="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a>      <span class="co">// fire, but don&#39;t forget</span></span>
<span id="cb9-14"><a href="#cb9-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="cb9-15"><a href="#cb9-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="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a>      <span class="co">// do something to handle exception</span></span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a>  <span class="co">// wait for all work nested within scope</span></span>
<span id="cb9-20"><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a>  <span class="co">// to finish</span></span>
<span id="cb9-21"><a href="#cb9-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="cb9-22"><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-23"><a href="#cb9-23" aria-hidden="true" tabindex="-1"></a>  <span class="co">// `ctx` is destroyed once nothing</span></span>
<span id="cb9-24"><a href="#cb9-24" aria-hidden="true" tabindex="-1"></a>  <span class="co">// references it</span></span>
<span id="cb9-25"><a href="#cb9-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

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

<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> context;</span>
<span id="cb10-4"><a href="#cb10-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="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><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>  context ctx;</span>
<span id="cb10-8"><a href="#cb10-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="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>      <span class="op">|</span> ex<span class="op">::</span>let_async_scope<span class="op">([&amp;](</span><span class="kw">auto</span> scope<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-10"><a href="#cb10-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="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>        <span class="co">// fire, but don&#39;t forget</span></span>
<span id="cb10-13"><a href="#cb10-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="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a>      <span class="op">}))</span>;</span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a>  <span class="co">// `ctx` is destroyed once nothing</span></span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a>  <span class="co">// references it</span></span>
<span id="cb10-18"><a href="#cb10-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_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_async_scope</code> are a step
forward towards Structured Concurrency<a href="#counting_scope-and-let_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_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_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="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><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>system_context ctx;</span>
<span id="cb11-5"><a href="#cb11-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="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-7"><a href="#cb11-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="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-9"><a href="#cb11-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 class="op">|</span> ex<span class="op">::</span>let_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-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>        <span class="dt">int</span> val <span class="op">=</span> <span class="dv">13</span>;</span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-12"><a href="#cb11-12" 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 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="cb11-13"><a href="#cb11-13" 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="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>        <span class="op">})</span>;</span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a>        <span class="co">// spawn the print sender on sch</span></span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a>        <span class="co">//</span></span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a>        <span class="co">// </span><span class="al">NOTE</span><span class="co">: if spawn throws, let_async_scope will capture the exception</span></span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a>        <span class="co">//       and propagate it through its set_error completion</span></span>
<span id="cb11-20"><a href="#cb11-20" 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="cb11-21"><a href="#cb11-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-22"><a href="#cb11-22" 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="cb11-23"><a href="#cb11-23" aria-hidden="true" tabindex="-1"></a>    <span class="op">})</span> <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="cb11-24"><a href="#cb11-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-25"><a href="#cb11-25" 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="cb11-26"><a href="#cb11-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-27"><a href="#cb11-27" 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="cb11-28"><a href="#cb11-28" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb11-29"><a href="#cb11-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-30"><a href="#cb11-30" aria-hidden="true" tabindex="-1"></a><span class="co">// &#39;let_async_scope&#39; ensures that, if all work is completed successfully, the result will be 13</span></span>
<span id="cb11-31"><a href="#cb11-31" aria-hidden="true" tabindex="-1"></a><span class="co">// `sync_wait` will throw whatever exception is thrown by the callable passed to `let_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="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><span class="kw">struct</span> my_window <span class="op">{</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">class</span> close_message <span class="op">{}</span>;</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-6"><a href="#cb12-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="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-8"><a href="#cb12-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="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-10"><a href="#cb12-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="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>        <span class="op">++</span>count;</span>
<span id="cb12-12"><a href="#cb12-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="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> onClickClose<span class="op">()</span> <span class="op">{</span></span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a>        <span class="op">++</span>count;</span>
<span id="cb12-17"><a href="#cb12-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="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb12-19"><a href="#cb12-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-20"><a href="#cb12-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="cb12-21"><a href="#cb12-21" aria-hidden="true" tabindex="-1"></a>        <span class="op">:</span> sch<span class="op">(</span>sch<span class="op">)</span></span>
<span id="cb12-22"><a href="#cb12-22" aria-hidden="true" tabindex="-1"></a>        , scope<span class="op">(</span>scope<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-23"><a href="#cb12-23" aria-hidden="true" tabindex="-1"></a>        <span class="co">// register this window with the windowing framework somehow so that</span></span>
<span id="cb12-24"><a href="#cb12-24" aria-hidden="true" tabindex="-1"></a>        <span class="co">// it starts receiving calls to onClickClose() and onMessage()</span></span>
<span id="cb12-25"><a href="#cb12-25" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb12-26"><a href="#cb12-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-27"><a href="#cb12-27" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>system_scheduler sch;</span>
<span id="cb12-28"><a href="#cb12-28" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>counting_scope<span class="op">::</span>token scope;</span>
<span id="cb12-29"><a href="#cb12-29" 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="cb12-30"><a href="#cb12-30" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb12-31"><a href="#cb12-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-32"><a href="#cb12-32" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb12-33"><a href="#cb12-33" aria-hidden="true" tabindex="-1"></a>    <span class="co">// keep track of all spawned work</span></span>
<span id="cb12-34"><a href="#cb12-34" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>counting_scope scope;</span>
<span id="cb12-35"><a href="#cb12-35" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>system_context ctx;</span>
<span id="cb12-36"><a href="#cb12-36" aria-hidden="true" tabindex="-1"></a>    <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb12-37"><a href="#cb12-37" 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="cb12-38"><a href="#cb12-38" 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="cb12-39"><a href="#cb12-39" aria-hidden="true" tabindex="-1"></a>        <span class="co">// do something with exception</span></span>
<span id="cb12-40"><a href="#cb12-40" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb12-41"><a href="#cb12-41" aria-hidden="true" tabindex="-1"></a>    <span class="co">// wait for all work nested within scope to finish</span></span>
<span id="cb12-42"><a href="#cb12-42" 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="cb12-43"><a href="#cb12-43" aria-hidden="true" tabindex="-1"></a>    <span class="co">// all resources are now safe to destroy</span></span>
<span id="cb12-44"><a href="#cb12-44" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> window<span class="op">.</span>count;</span>
<span id="cb12-45"><a href="#cb12-45" 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_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="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">namespace</span> ex <span class="op">=</span> std<span class="op">::</span>execution;</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-3"><a href="#cb13-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="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-5"><a href="#cb13-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="cb13-6"><a href="#cb13-6" 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_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="cb13-7"><a href="#cb13-7" 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> <span class="op">{</span> 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 class="op">})</span> <span class="op">|</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>               ex<span class="op">::</span>then<span class="op">([=]</span> <span class="op">{</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>                   <span class="co">// Create parallel work</span></span>
<span id="cb13-10"><a href="#cb13-10" 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="cb13-11"><a href="#cb13-11" 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="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a>                       <span class="co">//       result of let_async_scope through its set_error completion</span></span>
<span id="cb13-13"><a href="#cb13-13" 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="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a>                   <span class="op">}</span></span>
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a>               <span class="op">})</span>;</span>
<span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">})</span> <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="cb13-17"><a href="#cb13-17" 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="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-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="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-3"><a href="#cb14-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="cb14-4"><a href="#cb14-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="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>    listening_socket listen_sock<span class="op">{</span>port<span class="op">}</span>;</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">co_await</span> ex<span class="op">::</span>let_async_scope<span class="op">(</span>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="cb14-8"><a href="#cb14-8" 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="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>            <span class="co">// Accept a new connection</span></span>
<span id="cb14-10"><a href="#cb14-10" 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="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>            count<span class="op">++</span>;</span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-13"><a href="#cb14-13" 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="cb14-14"><a href="#cb14-14" 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="cb14-15"><a href="#cb14-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>just<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>data<span class="op">))</span> <span class="op">|</span></span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true" tabindex="-1"></a>                                  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 class="cf">return</span> handle_connection<span class="op">(</span>data<span class="op">)</span>; <span class="op">})</span>;</span>
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-18"><a href="#cb14-18" 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="cb14-19"><a href="#cb14-19" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb14-20"><a href="#cb14-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">})</span>;</span>
<span id="cb14-21"><a href="#cb14-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-22"><a href="#cb14-22" aria-hidden="true" tabindex="-1"></a>    <span class="co">// At this point, all the request handling is complete</span></span>
<span id="cb14-23"><a href="#cb14-23" aria-hidden="true" tabindex="-1"></a>    <span class="kw">co_return</span> count;</span>
<span id="cb14-24"><a href="#cb14-24" 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="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">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Feature<span class="op">&gt;</span></span>
<span id="cb15-2"><a href="#cb15-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="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-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="cb16-2"><a href="#cb16-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="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-4"><a href="#cb16-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="cb16-5"><a href="#cb16-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="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb16-7"><a href="#cb16-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="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">namespace</span> rsys <span class="op">{</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Call <span class="op">{</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb17-5"><a href="#cb17-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="cb17-6"><a href="#cb17-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="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>        scope_<span class="op">-&gt;</span>close<span class="op">()</span>;</span>
<span id="cb17-8"><a href="#cb17-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="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>        <span class="co">// other clean-up tasks here</span></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-13"><a href="#cb17-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="cb17-14"><a href="#cb17-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="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="kw">private</span><span class="op">:</span></span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a>    <span class="co">// an async scope shared between a call and its features</span></span>
<span id="cb17-18"><a href="#cb17-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="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a>    <span class="co">// each call has its own set of threads</span></span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true" tabindex="-1"></a>    ExecutionContext context_;</span>
<span id="cb17-21"><a href="#cb17-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-22"><a href="#cb17-22" aria-hidden="true" tabindex="-1"></a>    <span class="co">// the set of features this call supports</span></span>
<span id="cb17-23"><a href="#cb17-23" aria-hidden="true" tabindex="-1"></a>    FeatureBag features_;</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="kw">class</span> Camera <span class="op">{</span></span>
<span id="cb17-27"><a href="#cb17-27" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb17-28"><a href="#cb17-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="cb17-29"><a href="#cb17-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="cb17-30"><a href="#cb17-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-31"><a href="#cb17-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="cb17-32"><a href="#cb17-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="cb17-33"><a href="#cb17-33" aria-hidden="true" tabindex="-1"></a>            <span class="co">// the open or unused state when nest() is invoked, making</span></span>
<span id="cb17-34"><a href="#cb17-34" aria-hidden="true" tabindex="-1"></a>            <span class="co">// it safe to assume here that:</span></span>
<span id="cb17-35"><a href="#cb17-35" aria-hidden="true" tabindex="-1"></a>            <span class="co">//</span></span>
<span id="cb17-36"><a href="#cb17-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="cb17-37"><a href="#cb17-37" aria-hidden="true" tabindex="-1"></a>            <span class="co">//    execution context</span></span>
<span id="cb17-38"><a href="#cb17-38" aria-hidden="true" tabindex="-1"></a>            <span class="co">//  - Call::destroy() has not progressed past starting the</span></span>
<span id="cb17-39"><a href="#cb17-39" aria-hidden="true" tabindex="-1"></a>            <span class="co">//    join-sender so all the resources owned by the call</span></span>
<span id="cb17-40"><a href="#cb17-40" aria-hidden="true" tabindex="-1"></a>            <span class="co">//    are still valid</span></span>
<span id="cb17-41"><a href="#cb17-41" aria-hidden="true" tabindex="-1"></a>            <span class="co">//</span></span>
<span id="cb17-42"><a href="#cb17-42" aria-hidden="true" tabindex="-1"></a>            <span class="co">// if the nest() attempt fails because the join-sender has</span></span>
<span id="cb17-43"><a href="#cb17-43" aria-hidden="true" tabindex="-1"></a>            <span class="co">// started (or even if the Call has been completely destroyed)</span></span>
<span id="cb17-44"><a href="#cb17-44" aria-hidden="true" tabindex="-1"></a>            <span class="co">// then the sender returned from toggle() will safely do</span></span>
<span id="cb17-45"><a href="#cb17-45" aria-hidden="true" tabindex="-1"></a>            <span class="co">// nothing before completing with set_stopped()</span></span>
<span id="cb17-46"><a href="#cb17-46" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-47"><a href="#cb17-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="cb17-48"><a href="#cb17-48" aria-hidden="true" tabindex="-1"></a>                <span class="co">// toggle the camera</span></span>
<span id="cb17-49"><a href="#cb17-49" aria-hidden="true" tabindex="-1"></a>            <span class="op">})</span>;</span>
<span id="cb17-50"><a href="#cb17-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="cb17-51"><a href="#cb17-51" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb17-52"><a href="#cb17-52" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-53"><a href="#cb17-53" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb17-54"><a href="#cb17-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="cb17-55"><a href="#cb17-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="cb17-56"><a href="#cb17-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="cb17-57"><a href="#cb17-57" aria-hidden="true" tabindex="-1"></a>    Scheduler scheduler_;</span>
<span id="cb17-58"><a href="#cb17-58" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb17-59"><a href="#cb17-59" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-60"><a href="#cb17-60" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="co">// namespace rsys</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_async_scope</code> or
<code class="sourceCode default">counting_scope</code>.</p>
<h3 data-number="4.6.1" id="let_async_scope-with-spawn"><span class="header-section-number">4.6.1</span>
<code class="sourceCode default">let_async_scope</code> with
<code class="sourceCode default">spawn()</code><a href="#let_async_scope-with-spawn" 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>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="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> then<span class="op">([</span>sch, <span class="op">&amp;]()</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>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="cb18-11"><a href="#cb18-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="cb18-12"><a href="#cb18-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="cb18-13"><a href="#cb18-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="cb18-14"><a href="#cb18-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="cb18-15"><a href="#cb18-15" aria-hidden="true" tabindex="-1"></a>        <span class="co">// log error</span></span>
<span id="cb18-16"><a href="#cb18-16" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> just<span class="op">()</span>;</span>
<span id="cb18-17"><a href="#cb18-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">})</span>;</span>
<span id="cb18-18"><a href="#cb18-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb18-19"><a href="#cb18-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-20"><a href="#cb18-20" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb18-21"><a href="#cb18-21" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>scheduler sch;</span>
<span id="cb18-22"><a href="#cb18-22" aria-hidden="true" tabindex="-1"></a>    tree t <span class="op">=</span> make_tree<span class="op">()</span>;</span>
<span id="cb18-23"><a href="#cb18-23" aria-hidden="true" tabindex="-1"></a>    <span class="co">// let_async_scope will ensure all new work will be spawned on the</span></span>
<span id="cb18-24"><a href="#cb18-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="cb18-25"><a href="#cb18-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_async_scope; exceptions</span></span>
<span id="cb18-26"><a href="#cb18-26" aria-hidden="true" tabindex="-1"></a>    <span class="co">// will be handled by let_error instead.</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>ex<span class="op">::</span>just<span class="op">()</span> <span class="op">|</span> ex<span class="op">::</span>let_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="cb18-28"><a href="#cb18-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="cb18-29"><a href="#cb18-29" aria-hidden="true" tabindex="-1"></a>    <span class="op">}))</span>;</span>
<span id="cb18-30"><a href="#cb18-30" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="4.6.2" id="let_async_scope-with-spawn_future"><span class="header-section-number">4.6.2</span>
<code class="sourceCode default">let_async_scope</code> with
<code class="sourceCode default">spawn_future()</code><a href="#let_async_scope-with-spawn_future" class="self-link"></a></h3>
<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">struct</span> tree <span class="op">{</span></span>
<span id="cb19-2"><a href="#cb19-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="cb19-3"><a href="#cb19-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="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> data;</span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-7"><a href="#cb19-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="cb19-8"><a href="#cb19-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="cb19-9"><a href="#cb19-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="cb19-10"><a href="#cb19-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="cb19-11"><a href="#cb19-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="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a>            leftFut <span class="op">=</span> ex<span class="op">::</span>spawn_future<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="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-15"><a href="#cb19-15" 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="cb19-16"><a href="#cb19-16" aria-hidden="true" tabindex="-1"></a>            rightFut <span class="op">=</span> ex<span class="op">::</span>spawn_future<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="cb19-17"><a href="#cb19-17" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb19-18"><a href="#cb19-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-19"><a href="#cb19-19" 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="cb19-20"><a href="#cb19-20" 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="cb19-21"><a href="#cb19-21" aria-hidden="true" tabindex="-1"></a>    <span class="op">})</span>;</span>
<span id="cb19-22"><a href="#cb19-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb19-23"><a href="#cb19-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-24"><a href="#cb19-24" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb19-25"><a href="#cb19-25" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>scheduler sch;</span>
<span id="cb19-26"><a href="#cb19-26" aria-hidden="true" tabindex="-1"></a>    tree t <span class="op">=</span> make_tree<span class="op">()</span>;</span>
<span id="cb19-27"><a href="#cb19-27" aria-hidden="true" tabindex="-1"></a>    <span class="co">// let_async_scope will ensure all new work will be spawned on the</span></span>
<span id="cb19-28"><a href="#cb19-28" aria-hidden="true" tabindex="-1"></a>    <span class="co">// scope and will not be joined until all work is finished</span></span>
<span id="cb19-29"><a href="#cb19-29" aria-hidden="true" tabindex="-1"></a>    <span class="co">// </span><span class="al">NOTE</span><span class="co">: Exceptions will be surfaced to let_async_scope which will</span></span>
<span id="cb19-30"><a href="#cb19-30" aria-hidden="true" tabindex="-1"></a>    <span class="co">// call set_error with the exception_ptr</span></span>
<span id="cb19-31"><a href="#cb19-31" 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 class="op">|</span> ex<span class="op">::</span>let_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="cb19-32"><a href="#cb19-32" 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="cb19-33"><a href="#cb19-33" aria-hidden="true" tabindex="-1"></a>    <span class="op">}))</span>;</span>
<span id="cb19-34"><a href="#cb19-34" 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="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">struct</span> tree <span class="op">{</span></span>
<span id="cb20-2"><a href="#cb20-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="cb20-3"><a href="#cb20-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="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> data;</span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-7"><a href="#cb20-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="cb20-8"><a href="#cb20-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="cb20-9"><a href="#cb20-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="cb20-10"><a href="#cb20-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="cb20-11"><a href="#cb20-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-12"><a href="#cb20-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="cb20-13"><a href="#cb20-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="cb20-14"><a href="#cb20-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-15"><a href="#cb20-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="cb20-16"><a href="#cb20-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="cb20-17"><a href="#cb20-17" aria-hidden="true" tabindex="-1"></a>        <span class="co">// log error</span></span>
<span id="cb20-18"><a href="#cb20-18" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> just<span class="op">()</span>;</span>
<span id="cb20-19"><a href="#cb20-19" aria-hidden="true" tabindex="-1"></a>    <span class="op">})</span>;</span>
<span id="cb20-20"><a href="#cb20-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb20-21"><a href="#cb20-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-22"><a href="#cb20-22" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb20-23"><a href="#cb20-23" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>scheduler sch;</span>
<span id="cb20-24"><a href="#cb20-24" aria-hidden="true" tabindex="-1"></a>    tree t <span class="op">=</span> make_tree<span class="op">()</span>;</span>
<span id="cb20-25"><a href="#cb20-25" aria-hidden="true" tabindex="-1"></a>    ex<span class="op">::</span>counting_scope scope;</span>
<span id="cb20-26"><a href="#cb20-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="cb20-27"><a href="#cb20-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="cb20-28"><a href="#cb20-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 associated with the scope. Depending on the
policy, different guarantees can be provided in terms of the lifetimes
of the scope and any associated 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">nest()</code>,
<code class="sourceCode default">spawn()</code>, and
<code class="sourceCode default">spawn_future()</code> in terms of the
more fundamental async scope token interface, and leaving the
implementation of the abstract interface to concrete token types, this
paper’s design leaves the set of policies open to extension by user code
or future standards.</p>
<p>An async scope token’s implementation of the
<code class="sourceCode default">async_scope_token</code> concept:</p>
<ul>
<li>must allow an arbitrary sender to be wrapped without eagerly
starting the sender;</li>
<li>must not add new value or error completions when wrapping a
sender;</li>
<li>may fail to associate a new sender by returning
<code class="sourceCode default">false</code> from
<code class="sourceCode default">try_associate()</code>;</li>
<li>may fail to associate a new sender by eagerly throwing an exception
from either <code class="sourceCode default">try_associate()</code> or
<code class="sourceCode default">wrap()</code>;</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="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">namespace</span> std<span class="op">::</span>execution <span class="op">{</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-3"><a href="#cb21-3" 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="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> set_value<span class="op">()</span> <span class="op">&amp;&amp;</span> <span class="kw">noexcept</span>;</span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> set_stopped<span class="op">()</span> <span class="op">&amp;&amp;</span> <span class="kw">noexcept</span>;</span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Sigs<span class="op">&gt;</span></span>
<span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>spawn-future-receiver</em> <span class="op">{</span> <span class="co">// <em>exposition-only</em></span></span>
<span id="cb21-10"><a href="#cb21-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> T<span class="op">&gt;</span></span>
<span id="cb21-11"><a href="#cb21-11" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> set_value<span class="op">(</span>T<span class="op">&amp;&amp;...</span> t<span class="op">)</span> <span class="op">&amp;&amp;</span> <span class="kw">noexcept</span>;</span>
<span id="cb21-12"><a href="#cb21-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-13"><a href="#cb21-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> E<span class="op">&gt;</span></span>
<span id="cb21-14"><a href="#cb21-14" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> set_error<span class="op">(</span>E<span class="op">&amp;&amp;</span> e<span class="op">)</span> <span class="op">&amp;&amp;</span> <span class="kw">noexcept</span>;</span>
<span id="cb21-15"><a href="#cb21-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-16"><a href="#cb21-16" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> set_stopped<span class="op">()</span> <span class="op">&amp;&amp;</span> <span class="kw">noexcept</span>;</span>
<span id="cb21-17"><a href="#cb21-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb21-18"><a href="#cb21-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-19"><a href="#cb21-19" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Token<span class="op">&gt;</span></span>
<span id="cb21-20"><a href="#cb21-20" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> async_scope_token <span class="op">=</span></span>
<span id="cb21-21"><a href="#cb21-21" 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="cb21-22"><a href="#cb21-22" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span><span class="op">(</span>Token token<span class="op">)</span> <span class="op">{</span></span>
<span id="cb21-23"><a href="#cb21-23" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span> token<span class="op">.</span>try_associate<span class="op">()</span> <span class="op">}</span> <span class="op">-&gt;</span> same_as<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span>;</span>
<span id="cb21-24"><a href="#cb21-24" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span> token<span class="op">.</span>disassociate<span class="op">()</span> <span class="op">}</span> <span class="op">-&gt;</span> same_as<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;</span>;</span>
<span id="cb21-25"><a href="#cb21-25" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb21-26"><a href="#cb21-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-27"><a href="#cb21-27" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>async_scope_token Token, sender Sender<span class="op">&gt;</span></span>
<span id="cb21-28"><a href="#cb21-28" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <em>wrapped-sender-from</em> <span class="op">=</span> decay_t<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>declval<span class="op">&lt;</span>Token<span class="op">&amp;&gt;().</span>wrap<span class="op">(</span>declval<span class="op">&lt;</span>Sender<span class="op">&gt;()))&gt;</span>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb21-29"><a href="#cb21-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-30"><a href="#cb21-30" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> nest_t <span class="op">{</span> <em>unspecified</em> <span class="op">}</span>;</span>
<span id="cb21-31"><a href="#cb21-31" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> spawn_t <span class="op">{</span> <em>unspecified</em> <span class="op">}</span>;</span>
<span id="cb21-32"><a href="#cb21-32" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> spawn_future_t <span class="op">{</span> <em>unspecified</em> <span class="op">}</span>;</span>
<span id="cb21-33"><a href="#cb21-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-34"><a href="#cb21-34" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> nest_t nest<span class="op">{}</span>;</span>
<span id="cb21-35"><a href="#cb21-35" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> spawn_t spawn<span class="op">{}</span>;</span>
<span id="cb21-36"><a href="#cb21-36" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> spawn_future_t spawn_future<span class="op">{}</span>;</span>
<span id="cb21-37"><a href="#cb21-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-38"><a href="#cb21-38" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> simple_counting_scope <span class="op">{</span></span>
<span id="cb21-39"><a href="#cb21-39" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> token <span class="op">{</span></span>
<span id="cb21-40"><a href="#cb21-40" 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="cb21-41"><a href="#cb21-41" aria-hidden="true" tabindex="-1"></a>        Sender<span class="op">&amp;&amp;</span> wrap<span class="op">(</span>Sender<span class="op">&amp;&amp;</span> snd<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb21-42"><a href="#cb21-42" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-43"><a href="#cb21-43" aria-hidden="true" tabindex="-1"></a>        <span class="dt">bool</span> try_associate<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb21-44"><a href="#cb21-44" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-45"><a href="#cb21-45" aria-hidden="true" tabindex="-1"></a>        <span class="dt">void</span> disassociate<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb21-46"><a href="#cb21-46" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-47"><a href="#cb21-47" aria-hidden="true" tabindex="-1"></a>    <span class="kw">private</span><span class="op">:</span></span>
<span id="cb21-48"><a href="#cb21-48" aria-hidden="true" tabindex="-1"></a>        simple_counting_scope<span class="op">*</span> <em>scope</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb21-49"><a href="#cb21-49" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb21-50"><a href="#cb21-50" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-51"><a href="#cb21-51" aria-hidden="true" tabindex="-1"></a>    simple_counting_scope<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb21-52"><a href="#cb21-52" aria-hidden="true" tabindex="-1"></a>    <span class="op">~</span>simple_counting_scope<span class="op">()</span>;</span>
<span id="cb21-53"><a href="#cb21-53" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-54"><a href="#cb21-54" aria-hidden="true" tabindex="-1"></a>    <span class="co">// simple_counting_scope is immovable and uncopyable</span></span>
<span id="cb21-55"><a href="#cb21-55" 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="cb21-56"><a href="#cb21-56" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-57"><a href="#cb21-57" aria-hidden="true" tabindex="-1"></a>    token get_token<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb21-58"><a href="#cb21-58" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-59"><a href="#cb21-59" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> close<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb21-60"><a href="#cb21-60" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-61"><a href="#cb21-61" aria-hidden="true" tabindex="-1"></a>    sender <span class="kw">auto</span> join<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb21-62"><a href="#cb21-62" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb21-63"><a href="#cb21-63" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-64"><a href="#cb21-64" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> counting_scope <span class="op">{</span></span>
<span id="cb21-65"><a href="#cb21-65" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> token <span class="op">{</span></span>
<span id="cb21-66"><a href="#cb21-66" 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="cb21-67"><a href="#cb21-67" aria-hidden="true" tabindex="-1"></a>        sender <span class="kw">auto</span> wrap<span class="op">(</span>Sender<span class="op">&amp;&amp;</span> snd<span class="op">)</span> <span class="kw">const</span>;</span>
<span id="cb21-68"><a href="#cb21-68" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-69"><a href="#cb21-69" aria-hidden="true" tabindex="-1"></a>        <span class="dt">bool</span> try_associate<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb21-70"><a href="#cb21-70" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-71"><a href="#cb21-71" aria-hidden="true" tabindex="-1"></a>        <span class="dt">void</span> disassociate<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb21-72"><a href="#cb21-72" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-73"><a href="#cb21-73" aria-hidden="true" tabindex="-1"></a>    <span class="kw">private</span><span class="op">:</span></span>
<span id="cb21-74"><a href="#cb21-74" aria-hidden="true" tabindex="-1"></a>        counting_scope<span class="op">*</span> <em>scope</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb21-75"><a href="#cb21-75" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb21-76"><a href="#cb21-76" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-77"><a href="#cb21-77" aria-hidden="true" tabindex="-1"></a>    counting_scope<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb21-78"><a href="#cb21-78" aria-hidden="true" tabindex="-1"></a>    <span class="op">~</span>counting_scope<span class="op">()</span>;</span>
<span id="cb21-79"><a href="#cb21-79" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-80"><a href="#cb21-80" aria-hidden="true" tabindex="-1"></a>    <span class="co">// counting_scope is immovable and uncopyable</span></span>
<span id="cb21-81"><a href="#cb21-81" 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="cb21-82"><a href="#cb21-82" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-83"><a href="#cb21-83" aria-hidden="true" tabindex="-1"></a>    token get_token<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb21-84"><a href="#cb21-84" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-85"><a href="#cb21-85" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> close<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb21-86"><a href="#cb21-86" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-87"><a href="#cb21-87" 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="cb21-88"><a href="#cb21-88" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-89"><a href="#cb21-89" aria-hidden="true" tabindex="-1"></a>    sender <span class="kw">auto</span> join<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb21-90"><a href="#cb21-90" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb21-91"><a href="#cb21-91" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-92"><a href="#cb21-92" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="co">// namespace std::execution</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="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">template</span> <span class="op">&lt;</span><span class="kw">class</span> Token<span class="op">&gt;</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> async_scope_token <span class="op">=</span></span>
<span id="cb22-3"><a href="#cb22-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="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span><span class="op">(</span>Token token<span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span> token<span class="op">.</span>try_associate<span class="op">()</span> <span class="op">}</span> <span class="op">-&gt;</span> same_as<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span>;</span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span> token<span class="op">.</span>disassociate<span class="op">()</span> <span class="op">}</span> <span class="op">-&gt;</span> same_as<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;</span>;</span>
<span id="cb22-7"><a href="#cb22-7" 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 async scope that
behaves like a reference-to-async-scope; tokens are no-throw copyable
and movable, and it is undefined behaviour to invoke any methods on a
token that has outlived its scope.</p>
<p>The <code class="sourceCode default">try_associate()</code> method on
a token attempts to create a new association with the scope;
<code class="sourceCode default">try_associate()</code> returns
<code class="sourceCode default">true</code> when the association is
successful, and it may either return
<code class="sourceCode default">false</code> or throw an exception to
indicate failure. Returning
<code class="sourceCode default">false</code> will generally lead to
algorithms that operate on tokens behaving as if provided a sender that
completes immediately with
<code class="sourceCode default">set_stopped()</code>, leading to
rejected work being discarded as a “no-op”. Throwing an exception will
generally lead to that exception escaping from the calling
algorithm.</p>
<p>The <code class="sourceCode default">disassociate()</code> method
removes a previously-established assocation with the scope.
<code class="sourceCode default">disassociate()</code> must be called
exactly once for every call to
<code class="sourceCode default">try_associate()</code> that returns
<code class="sourceCode default">true</code>; it is undefined behaviour
to do otherwise.</p>
<p>Tokens also have a <code class="sourceCode default">wrap()</code>
method that takes and returns a sender. The
<code class="sourceCode default">wrap()</code> method gives the token an
opportunity to modify the input sender’s behaviour in a scope-specific
way. The proposed <code class="sourceCode default">counting_scope</code>
uses this opportunity to associate the input sender with a stop token
that the scope can use to request stop on all outstanding operations
associated within the scope.</p>
<p>In order to provide the Strong Exception Guarantee, the algorithms
proposed in this paper invoke
<code class="sourceCode default">token.wrap(snd)</code> before invoking
<code class="sourceCode default">token.try_associate()</code>. Other
algorithms written in terms of
<code class="sourceCode default">async_scope_token</code> should do the
same.</p>
<p><em>Note</em>: Wrapping the sender before creating an association
means that, when <code class="sourceCode default">try_associate()</code>
returns <code class="sourceCode default">false</code>, the work to wrap
the sender must be discarded. We could, instead, try to create the
association first and only wrap the sender when successful; this would
be more efficient but would limit us to providing the Basic Exception
Guarantee.</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="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="kw">struct</span> nest_t <span class="op">{</span> <em>unspecified</em> <span class="op">}</span>;</span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> nest_t nest<span class="op">{}</span>;</span></code></pre></div>
<p><code class="sourceCode default">nest</code> is a CPO with the
following signature:</p>
<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>sender <span class="kw">auto</span> nest<span class="op">(</span>sender <span class="kw">auto</span><span class="op">&amp;&amp;</span>, async_scope_token <span class="kw">auto</span><span class="op">)</span> <span class="kw">noexcept</span><span class="op">(...)</span>;</span></code></pre></div>
<p>When successful, <code class="sourceCode default">nest()</code>
creates an association with the given token’s scope and returns an
“associated” nest-sender that behaves the same as its input sender, with
the following additional effects:</p>
<ul>
<li>the association ends when the nest-sender is destroyed or, if it is
connected, when the resulting operation state is destroyed; and</li>
<li>whatever effects are added by the token’s
<code class="sourceCode default">wrap()</code> method.</li>
</ul>
<p>When unsuccessful, <code class="sourceCode default">nest()</code>
will either return an “unassociated” nest-sender or it will allow any
thrown exceptions to escape.</p>
<p>When <code class="sourceCode default">nest()</code> returns an
associated nest-sender:</p>
<ul>
<li>connecting and starting the associated nest-sender connects and
starts the given sender; and</li>
<li>the associated nest-sender has exactly the same completions as the
input sender.</li>
</ul>
<p>When <code class="sourceCode default">nest()</code> returns an
unassociated nest-sender:</p>
<ul>
<li>the input sender is discarded and will never be connected or
started; and</li>
<li>the unassociated nest-sender will only complete with
<code class="sourceCode default">set_stopped()</code>.</li>
</ul>
<p>Given an <code class="sourceCode default">async_scope_token</code>,
<code class="sourceCode default">token</code>, and a sender,
<code class="sourceCode default">snd</code>,
<code class="sourceCode default">nest(snd, token)</code> is
expression-equivalent to <code class="sourceCode default"><em>make-sender</em>(nest, <em>nest-data</em>{snd, token})</code>,
where <em><code class="sourceCode default">nest-data</code></em> is an
exposition-only class whose constructor performs the following
operations in the following order:</p>
<ol type="1">
<li>store the result of
<code class="sourceCode default">token.wrap(snd)</code> in a member
variable</li>
<li>invoke <code class="sourceCode default">token.try_associate()</code>
<ol type="a">
<li>if the result is <code class="sourceCode default">false</code> then
destroy the previously stored result of
<code class="sourceCode default">token.wrap(snd)</code>; the nest-sender
under construction is unassociated.</li>
<li>otherwise, the nest-sender under construction is associated.</li>
</ol></li>
</ol>
<p>Any exceptions thrown during the evaluation of the constructor are
allowed to escape; nevertheless,
<code class="sourceCode default">nest()</code> provides the Strong
Exception Guarantee.</p>
<p>An associated nest-sender has many properties of an RAII handle:</p>
<ul>
<li>constructing an instance acquires a “resource” (the association with
the scope)</li>
<li>destructing an instance releases the same resource</li>
<li>moving an instance into another transfers ownership of the resource
from the source to the destination</li>
<li>etc.</li>
</ul>
<p>Copying a nest-sender is possible if the sender it is wrapping is
copyable but the copying process is a bit unusual because of the
<code class="sourceCode default">async_scope_token</code> it contains.
If the sender, <code class="sourceCode default">snd</code>, provided to
<code class="sourceCode default">nest()</code> is copyable then the
resulting nest-sender is also copyable, with the following rules:</p>
<ul>
<li>copying an unassociated nest-sender invariably produces a new
unassociated nest-sender; and</li>
<li>copying an associated nest-sender requires copying the
<em><code class="sourceCode default">nest-data</code></em> it contains
and the <em><code class="sourceCode default">nest-data</code></em>
copy-constructor proceeds as follows:
<ol type="1">
<li>copy the token from the source
<em><code class="sourceCode default">nest-data</code></em> to the
destination; and</li>
<li>if <code class="sourceCode default">token.try_associate()</code>
returns <code class="sourceCode default">true</code>, copy the sender
from the source
<em><code class="sourceCode default">nest-data</code></em> to the
destination
<ul>
<li>if the sender is copied in step 2 then the new nest-sender is
associated; otherwise, it’s unassociated</li>
</ul></li>
</ol></li>
</ul>
<p><em>Note</em>: copying an associated nest-sender may produce an
unassociated nest-sender however this observable difference is not a
salient property of the nest-sender. A nest-sender is similar to a
stateful
<code class="sourceCode default">std::function&lt;T()&gt;</code> for
some <code class="sourceCode default">T</code>; it is expected that
invoking a copy of such an object may produce a different result than
invoking the original.</p>
<p>When a nest-sender has a copy constructor, it provides the Strong
Exception Guarantee.</p>
<p>When connecting an unassociated nest-sender, the resulting
<em><code class="sourceCode default">operation-state</code></em>
completes immediately with
<code class="sourceCode default">set_stopped()</code> when started.</p>
<p>When connecting an associated nest-sender, there are four possible
outcomes:</p>
<ol type="1">
<li>the nest-sender is rvalue connected, which infallibly moves the
sender’s association from the sender to the
<em><code class="sourceCode default">operation-state</code></em></li>
<li>the nest-sender is lvalue connected, in which case the new
<em><code class="sourceCode default">operation-state</code></em> needs
its own association with the nest-sender’s scope, which requires calling
<code class="sourceCode default">try_associate()</code> again and it
may:
<ol type="a">
<li>succeed by returning
<code class="sourceCode default">true</code>;</li>
<li>fail by returning <code class="sourceCode default">false</code>, in
which case the
<em><code class="sourceCode default">operation-state</code></em> behaves
as if it were constructed from an unassociated nest-sender; or</li>
<li>fail by throwing an exception, in which case the exception escapes
from the call to connect.</li>
</ol></li>
</ol>
<p>An <em><code class="sourceCode default">operation-state</code></em>
with its own association must invoke
<code class="sourceCode default">token.disassociate()</code> as the last
step of the
<em><code class="sourceCode default">operation-state</code></em>’s
destructor.</p>
<p>Note: the timing of when an associated
<em><code class="sourceCode default">operation-state</code></em> ends
its association with the scope is chosen to avoid exposing user code to
dangling references. Scopes are expected to serve as mechanisms for
signaling when it is safe to destroy shared resources being protected by
the scope. Ending any given association with a scope may lead to that
scope signaling that the protected resources can be destroyed so a
nest-sender’s
<em><code class="sourceCode default">operation-state</code></em> must
not permit that signal to be sent until the
<em><code class="sourceCode default">operation-state</code></em> is
definitely finished accessing the shared resources, which is at the end
of the
<em><code class="sourceCode default">operation-state</code></em>’s
destructor.</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>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="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="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Env<span class="op">&gt;</span></span>
<span id="cb25-2"><a href="#cb25-2" 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="cb25-3"><a href="#cb25-3" 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="cb25-4"><a href="#cb25-4" 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="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-7"><a href="#cb25-7" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> spawn_t <span class="op">{</span> <em>unspecified</em> <span class="op">}</span>;</span>
<span id="cb25-8"><a href="#cb25-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-9"><a href="#cb25-9" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> spawn_t spawn<span class="op">{}</span>;</span></code></pre></div>
<p><code class="sourceCode default">spawn</code> is a CPO with the
following signature:</p>
<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">template</span> <span class="op">&lt;</span>sender Sender, async_scope_token Token, <span class="kw">class</span> Env <span class="op">=</span> empty_env<span class="op">&gt;</span></span>
<span id="cb26-2"><a href="#cb26-2" 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><code class="sourceCode default">spawn</code> attempts to associate
the given sender with the given scope token’s scope. On success, the
given sender is eagerly started. On failure, either the sender is
discarded and no further work happens or
<code class="sourceCode default">spawn()</code> throws.</p>
<p>Starting the given sender without waiting for it to finish requires 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(token.wrap(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;void&gt;</code>.</li>
</ul>
<p><code class="sourceCode default">spawn()</code> proceeds with the
following steps in the following order:</p>
<ol type="1">
<li>an environment, <code class="sourceCode default">senv</code>, is
chosen:
<ul>
<li>if <code class="sourceCode default">get_allocator(env)</code> is
valid then <code class="sourceCode default">senv</code> is
<code class="sourceCode default">env</code>;</li>
<li>otherwise, if <code class="sourceCode default">get_allocator(get_env(token.wrap(snd)))</code>
is valid then <code class="sourceCode default">senv</code> is the
expression <code class="sourceCode default"><em>JOIN-ENV</em>(env, prop(get_allocator, alloc))</code>,
where <code class="sourceCode default">alloc</code> is the chosen
allocator;</li>
<li>otherwise, <code class="sourceCode default">senv</code> is
<code class="sourceCode default">env</code>.</li>
</ul></li>
<li>the type of the object to dynamically allocate is computed, say
<code class="sourceCode default">op_t</code>;
<code class="sourceCode default">op_t</code> contains
<ul>
<li>an
<em><code class="sourceCode default">operation-state</code></em>;</li>
<li>an allocator of the chosen type; and</li>
<li>a copy of <code class="sourceCode default">token</code>.</li>
</ul></li>
<li>an <code class="sourceCode default">op_t</code> is dynamically
allocated by the <em>Allocator</em> chosen as described above</li>
<li>the fields of the <code class="sourceCode default">op_t</code> are
initialized in the following order:
<ol type="a">
<li>the <em><code class="sourceCode default">operation-state</code></em>
within the allocated <code class="sourceCode default">op_t</code> is
initialized with the result of <code class="sourceCode default">connect(write_env(token.wrap(std::forward&lt;Sender&gt;(snd)), <em>spawn-receiver</em>{...}, senv))</code>;</li>
<li>the allocator is initialized with a copy of the allocator used to
allocate the <code class="sourceCode default">op_t</code>; and</li>
<li>the token is initialized with a copy of
<code class="sourceCode default">token</code>.</li>
</ol></li>
<li>if <code class="sourceCode default">token.try_associate()</code>
returns <code class="sourceCode default">true</code> then the
<em><code class="sourceCode default">operation-state</code></em> is
started; otherwise, the <code class="sourceCode default">op_t</code> is
destroyed and deallocated.</li>
</ol>
<p>Any exceptions thrown during the execution of
<code class="sourceCode default">spawn()</code> are allowed to escape;
nevertheless, <code class="sourceCode default">spawn()</code> provides
the Strong Exception Guarantee.</p>
<p>Upon completion of the
<em><code class="sourceCode default">operation-state</code></em>, the
<em><code class="sourceCode default">spawn-receiver</code></em> performs
the following steps:</p>
<ol type="1">
<li>move the allocator and token from the
<code class="sourceCode default">op_t</code> into local variables;</li>
<li>destroy the
<em><code class="sourceCode default">operation-state</code></em>;</li>
<li>use the local copy of the allocator to deallocate the
<code class="sourceCode default">op_t</code>;</li>
<li>destroy the local copy of the allocator; and</li>
<li>invoke <code class="sourceCode default">token.disassociate()</code>
on the local copy of the token.</li>
</ol>
<p>Performing step 5 last ensures that all possible references to
resources protected by the scope, including possibly the allocator, are
no longer in use before dissociating from the scope.</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 lifetime of the work described by the sender. The
<code class="sourceCode default">simple_counting_scope</code> and
<code class="sourceCode default">counting_scope</code> described in this
paper use this opportunity to keep a count of spawned senders that
haven’t finished, and to prevent new senders from being spawned once the
scope has been closed.</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="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="op">...</span></span>
<span id="cb27-2"><a href="#cb27-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="cb27-3"><a href="#cb27-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="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Sigs<span class="op">&gt;</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>spawn-future-receiver</em> <span class="op">{</span> <span class="co">// <em>exposition-only</em></span></span>
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> T<span class="op">&gt;</span></span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> set_value<span class="op">(</span>T<span class="op">&amp;&amp;...</span> t<span class="op">)</span> <span class="op">&amp;&amp;</span> <span class="kw">noexcept</span>;</span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> E<span class="op">&gt;</span></span>
<span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> set_error<span class="op">(</span>E<span class="op">&amp;&amp;</span> e<span class="op">)</span> <span class="op">&amp;&amp;</span> <span class="kw">noexcept</span>;</span>
<span id="cb28-8"><a href="#cb28-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-9"><a href="#cb28-9" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> set_stopped<span class="op">()</span> <span class="op">&amp;&amp;</span> <span class="kw">noexcept</span>;</span>
<span id="cb28-10"><a href="#cb28-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb28-11"><a href="#cb28-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-12"><a href="#cb28-12" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> spawn_future_t <span class="op">{</span> <em>unspecified</em> <span class="op">}</span>;</span>
<span id="cb28-13"><a href="#cb28-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-14"><a href="#cb28-14" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> spawn_future_t spawn_future<span class="op">{}</span>;</span></code></pre></div>
<p><code class="sourceCode default">spawn_future</code> is a CPO with
the following signature:</p>
<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><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, async_scope_token Token, <span class="kw">class</span> Env <span class="op">=</span> empty_env<span class="op">&gt;</span></span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a>sender <span class="kw">auto</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><code class="sourceCode default">spawn_future</code> attempts to
associate the given sender with the given scope token’s scope. On
success, the given sender is eagerly started and
<code class="sourceCode default">spawn_future</code> returns a sender
that provides access to the result of the given sender. On failure,
either <code class="sourceCode default">spawn_future</code> returns a
sender that unconditionally completes with
<code class="sourceCode default">set_stopped()</code> or it throws.</p>
<p>Similar to <code class="sourceCode default">spawn()</code>, starting
the given 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(token.wrap(snd)))</code>
if that is a valid expression, otherwise use a
<code class="sourceCode default">std::allocator&lt;void&gt;</code>.</p>
<p>Compared to <code class="sourceCode default">spawn()</code>, the
dynamically allocated state is more complicated because it must contain
storage for the result of the given sender, however it eventually
completes, and synchronization facilities for resolving the race between
the given sender’s production of its result and the returned sender’s
consumption or abandonment of that result.</p>
<p>Unlike <code class="sourceCode default">spawn()</code>,
<code class="sourceCode default">spawn_future()</code> returns a sender
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. 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. 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.</p>
<p><code class="sourceCode default">spawn_future(snd, token, env)</code>
proceeds with the following steps in the following order:</p>
<ol type="1">
<li>An allocator, <code class="sourceCode default">alloc</code>, is
chosen as described above.</li>
<li>A stop token, <code class="sourceCode default">stok</code>, is
created such that it receives stop requests sent by the returned future
<em>and</em> any stop requests received by the stop token returned from
<code class="sourceCode default">get_stop_token(env)</code>;</li>
<li>An environment, <code class="sourceCode default">senv</code>, is
chosen as follows:
<ul>
<li>if <code class="sourceCode default">alloc</code> is
<code class="sourceCode default">get_allocator(env)</code> then
<code class="sourceCode default">senv</code> is <code class="sourceCode default"><em>JOIN-ENV</em>(prop(get_stop_token, stok), env)</code>;</li>
<li>otherwise, if <code class="sourceCode default">alloc</code> is <code class="sourceCode default">get_allocator(get_env(token.wrap(snd)))</code>
then <code class="sourceCode default">senv</code> is <code class="sourceCode default"><em>JOIN-ENV</em>(<em>JOIN-ENV</em>(prop(get_allocator, alloc), prop(get_stop_token, stok)), env)</code>;</li>
<li>otherwise, <code class="sourceCode default">senv</code> is <code class="sourceCode default"><em>JOIN-ENV</em>(prop(get_stop_token, stok), env)</code>.</li>
</ul></li>
<li>Storage for the spawned sender’s state is dynamically allocated
using <code class="sourceCode default">alloc</code>; the address of this
storage is known as <code class="sourceCode default">op</code>.</li>
<li>The state for the spawned sender is constructed in the allocated
storage
<ul>
<li><p>A subset of this state is an
<em><code class="sourceCode default">operation-state</code></em> created
with the following expression:</p>
<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="fu">connect</span><span class="op">(</span></span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a>    write_env<span class="op">(</span>token<span class="op">.</span>wrap<span class="op">(</span>snd<span class="op">)</span>, senv<span class="op">)</span>,</span>
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a>    <em>spawn-future-receiver</em><span class="op">&lt;</span><em>completion-signatures-of</em><span class="op">&lt;</span>Sender<span class="op">&gt;&gt;{</span>op<span class="op">})</span>;</span></code></pre></div></li>
<li><p>After the last field in the dynamically allocated state is
initialized,</p>
<ul>
<li>If <code class="sourceCode default">token.try_associate()</code>
returns <code class="sourceCode default">true</code> then the
<em><code class="sourceCode default">operation-state</code></em> within
the allocated state is started.</li>
<li>Otherwise the dynamically-allocated state is marked as having
completed with
<code class="sourceCode default">set_stopped()</code>.</li>
</ul></li>
</ul></li>
<li>A sender is returned that, when connected and started, will complete
with the result of the eagerly-started work.</li>
</ol>
<p>Any exceptions thrown during the execution of
<code class="sourceCode default">spawn_future()</code> are allowed to
escape; nevertheless,
<code class="sourceCode default">spawn_future()</code> provides the
Strong Exception Guarantee.</p>
<p>Given a sender returned from
<code class="sourceCode default">spawn_future()</code>,
<code class="sourceCode default">fs</code>, if
<code class="sourceCode default">fs</code> is destroyed without being
connected, or if it <em>is</em> connected and the resulting
<em><code class="sourceCode default">operation-state</code></em>,
<code class="sourceCode default">fsop</code>, is destroyed without being
started, then the eagerly-started work is “abandoned”.</p>
<p>Abandoning the eagerly-started work means:</p>
<ul>
<li>a stop request is sent to the running
<em><code class="sourceCode default">operation-state</code></em>;</li>
<li>any result produced by the running
<em><code class="sourceCode default">operation-state</code></em> is
discarded when the operation completes; and</li>
<li>after the operation completes, the dynamically-allocated state is
“cleaned up”.</li>
</ul>
<p>Cleaning up the dynamically-allocated state means doing the
following, in order:</p>
<ol type="1">
<li>the allocator and token in the state are moved into local
variables;</li>
<li>the state is destroyed;</li>
<li>the dynamic allocation is deallocated with the local copy of the
allocator;</li>
<li>the local copy of the allocator is destroyed; and</li>
<li><code class="sourceCode default">token.disassociate()</code> is
invoked on the local copy of the token.</li>
</ol>
<p>When <code class="sourceCode default">fsop</code> is started, if
<code class="sourceCode default">fsop</code> receives a stop request
from its receiver before the eagerly-started work has completed then an
attempt is made to abandon the eagerly-started work. Note that it’s
possible for the eagerly-started work to complete while
<code class="sourceCode default">fsop</code> is requesting stop; once
the stop request has been delivered, either
<code class="sourceCode default">fsop</code> completes with the result
of the eagerly-started work if it’s ready, or it completes with
<code class="sourceCode default">set_stopped()</code> without waiting
for the eagerly-started work to complete.</p>
<p>When <code class="sourceCode default">fsop</code> is started and does
not receive a stop request from its receiver,
<code class="sourceCode default">fsop</code> completes after the
eagerly-started work completes with the same completion. Once
<code class="sourceCode default">fsop</code> completes, it cleans up the
dynamically-allocated state.</p>
<p><code class="sourceCode default">spawn_future</code> 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 lifetime of the work described by the sender. The
<code class="sourceCode default">simple_counting_scope</code> and
<code class="sourceCode default">counting_scope</code> described in this
paper use this opportunity to keep a count of given senders that haven’t
finished, and to prevent new senders from being started once the scope
has been closed.</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>Usage example:</p>
<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="op">...</span></span>
<span id="cb31-2"><a href="#cb31-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>, token<span class="op">)</span> <span class="op">|</span> then<span class="op">(</span>continue_fun<span class="op">)</span>;</span>
<span id="cb31-3"><a href="#cb31-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="cb31-4"><a href="#cb31-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>, token<span class="op">)</span>;</span>
<span id="cb31-5"><a href="#cb31-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="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">class</span> simple_counting_scope <span class="op">{</span></span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> token <span class="op">{</span></span>
<span id="cb32-3"><a href="#cb32-3" 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="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a>        Sender<span class="op">&amp;&amp;</span> wrap<span class="op">(</span>Sender<span class="op">&amp;&amp;</span> snd<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a>        <span class="dt">bool</span> try_associate<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb32-7"><a href="#cb32-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-8"><a href="#cb32-8" aria-hidden="true" tabindex="-1"></a>        <span class="dt">void</span> disassociate<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb32-9"><a href="#cb32-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-10"><a href="#cb32-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">private</span><span class="op">:</span></span>
<span id="cb32-11"><a href="#cb32-11" aria-hidden="true" tabindex="-1"></a>        simple_counting_scope<span class="op">*</span> <em>scope</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb32-12"><a href="#cb32-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb32-13"><a href="#cb32-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-14"><a href="#cb32-14" aria-hidden="true" tabindex="-1"></a>    simple_counting_scope<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb32-15"><a href="#cb32-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">~</span>simple_counting_scope<span class="op">()</span>;</span>
<span id="cb32-16"><a href="#cb32-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-17"><a href="#cb32-17" aria-hidden="true" tabindex="-1"></a>    <span class="co">// simple_counting_scope is immovable and uncopyable</span></span>
<span id="cb32-18"><a href="#cb32-18" 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="cb32-19"><a href="#cb32-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-20"><a href="#cb32-20" aria-hidden="true" tabindex="-1"></a>    token get_token<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb32-21"><a href="#cb32-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-22"><a href="#cb32-22" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> close<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb32-23"><a href="#cb32-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-24"><a href="#cb32-24" aria-hidden="true" tabindex="-1"></a>    sender <span class="kw">auto</span> join<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb32-25"><a href="#cb32-25" 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,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBjb250ZW50U3R5bGVUeXBlPSJ0ZXh0L2NzcyIgZGF0YS1kaWFncmFtLXR5cGU9IlNUQVRFIiBoZWlnaHQ9IjkzOXB4IiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJub25lIiBzdHlsZT0id2lkdGg6OTAwcHg7aGVpZ2h0OjkzOXB4O2JhY2tncm91bmQ6I0ZGRkZGRjsiIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDkwMCA5MzkiIHdpZHRoPSI5MDBweCIgem9vbUFuZFBhbj0ibWFnbmlmeSI+PGRlZnMvPjxnPjxnIGlkPSJ1bnVzZWQiPjxyZWN0IGZpbGw9IiNGMUYxRjEiIGhlaWdodD0iNzguODg2NyIgcng9IjEyLjUiIHJ5PSIxMi41IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiIHdpZHRoPSIxOTQuMTUyMyIgeD0iMzc0IiB5PSI4NyIvPjxsaW5lIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgeDE9IjM3NCIgeDI9IjU2OC4xNTIzIiB5MT0iMTEzLjQ4ODMiIHkyPSIxMTMuNDg4MyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjE0IiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjQ5LjgxMzUiIHg9IjQ0Ni4xNjk0IiB5PSIxMDUuNTM1MiI+dW51c2VkPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjU3LjYyMTEiIHg9IjM3OSIgeT0iMTMwLjA4OTgiPmNvdW50ID0gMDwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIxNzQuMTUyMyIgeD0iMzc5IiB5PSIxNDQuMjIyNyI+dHJ5X2Fzc29jaWF0ZSgpIGNhbiByZXR1cm4gdHJ1ZTwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI5OS4yNTIiIHg9IjM3OSIgeT0iMTU4LjM1NTUiPmpvaW4oKSBub3QgbmVlZGVkPC90ZXh0PjwvZz48ZyBpZD0ib3BlbiI+PHJlY3QgZmlsbD0iI0YxRjFGMSIgaGVpZ2h0PSI3OC44ODY3IiByeD0iMTIuNSIgcnk9IjEyLjUiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgd2lkdGg9IjE5NC4xNTIzIiB4PSIyMjkiIHk9IjI0Mi44OCIvPjxsaW5lIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgeDE9IjIyOSIgeDI9IjQyMy4xNTIzIiB5MT0iMjY5LjM2ODMiIHkyPSIyNjkuMzY4MyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjE0IiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjMzLjg5OTQiIHg9IjMwOS4xMjY1IiB5PSIyNjEuNDE1MiI+b3BlbjwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI1Ny42MjciIHg9IjIzNCIgeT0iMjg1Ljk2OTgiPmNvdW50ICYjODgwNTsgMDwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIxNzQuMTUyMyIgeD0iMjM0IiB5PSIzMDAuMTAyNyI+dHJ5X2Fzc29jaWF0ZSgpIGNhbiByZXR1cm4gdHJ1ZTwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI3Ni4xNDg0IiB4PSIyMzQiIHk9IjMxNC4yMzU1Ij5qb2luKCkgbmVlZGVkPC90ZXh0PjwvZz48ZyBpZD0iY2xvc2VkIj48cmVjdCBmaWxsPSIjRjFGMUYxIiBoZWlnaHQ9Ijc4Ljg4NjciIHJ4PSIxMi41IiByeT0iMTIuNSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7IiB3aWR0aD0iMTgwLjAzMTMiIHg9IjIzNi4wNiIgeT0iNDEzLjc3Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7IiB4MT0iMjM2LjA2IiB4Mj0iNDE2LjA5MTMiIHkxPSI0NDAuMjU4MyIgeTI9IjQ0MC4yNTgzIi8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTQiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNDMuNTY1NCIgeD0iMzA0LjI5MjkiIHk9IjQzMi4zMDUyIj5jbG9zZWQ8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNTcuNjI3IiB4PSIyNDEuMDYiIHk9IjQ1Ni44NTk4Ij5jb3VudCAmIzg4MDU7IDA8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTYwLjAzMTMiIHg9IjI0MS4wNiIgeT0iNDcwLjk5MjciPnRyeV9hc3NvY2lhdGUoKSByZXR1cm5zIGZhbHNlPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9Ijc2LjE0ODQiIHg9IjI0MS4wNiIgeT0iNDg1LjEyNTUiPmpvaW4oKSBuZWVkZWQ8L3RleHQ+PC9nPjxnIGlkPSJvcGVuX2FuZF9qb2luaW5nIj48cmVjdCBmaWxsPSIjRjFGMUYxIiBoZWlnaHQ9Ijc4Ljg4NjciIHJ4PSIxMi41IiByeT0iMTIuNSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7IiB3aWR0aD0iMTk0LjE1MjMiIHg9IjciIHk9IjQxMy43NyIvPjxsaW5lIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgeDE9IjciIHgyPSIyMDEuMTUyMyIgeTE9IjQ0MC4yNTgzIiB5Mj0iNDQwLjI1ODMiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIxMjIuMzkwNiIgeD0iNDIuODgwOSIgeT0iNDMyLjMwNTIiPm9wZW4tYW5kLWpvaW5pbmc8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNTcuNjI3IiB4PSIxMiIgeT0iNDU2Ljg1OTgiPmNvdW50ICYjODgwNTsgMDwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIxNzQuMTUyMyIgeD0iMTIiIHk9IjQ3MC45OTI3Ij50cnlfYXNzb2NpYXRlKCkgY2FuIHJldHVybiB0cnVlPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9Ijc5LjE4OTUiIHg9IjEyIiB5PSI0ODUuMTI1NSI+am9pbigpIHJ1bm5pbmc8L3RleHQ+PC9nPjxnIGlkPSJjbG9zZWRfYW5kX2pvaW5pbmciPjxyZWN0IGZpbGw9IiNGMUYxRjEiIGhlaWdodD0iNzguODg2NyIgcng9IjEyLjUiIHJ5PSIxMi41IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiIHdpZHRoPSIxODAuMDMxMyIgeD0iMjc0LjA2IiB5PSI1ODQuNjYiLz48bGluZSBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiIHgxPSIyNzQuMDYiIHgyPSI0NTQuMDkxMyIgeTE9IjYxMS4xNDgzIiB5Mj0iNjExLjE0ODMiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIxMzIuMDU2NiIgeD0iMjk4LjA0NzMiIHk9IjYwMy4xOTUyIj5jbG9zZWQtYW5kLWpvaW5pbmc8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNTcuNjI3IiB4PSIyNzkuMDYiIHk9IjYyNy43NDk4Ij5jb3VudCAmIzg4MDU7IDA8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTYwLjAzMTMiIHg9IjI3OS4wNiIgeT0iNjQxLjg4MjciPnRyeV9hc3NvY2lhdGUoKSByZXR1cm5zIGZhbHNlPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9Ijc5LjE4OTUiIHg9IjI3OS4wNiIgeT0iNjU2LjAxNTUiPmpvaW4oKSBydW5uaW5nPC90ZXh0PjwvZz48ZyBpZD0idW51c2VkX2FuZF9jbG9zZWQiPjxyZWN0IGZpbGw9IiNGMUYxRjEiIGhlaWdodD0iNzguODg2NyIgcng9IjEyLjUiIHJ5PSIxMi41IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiIHdpZHRoPSIxODAuMDMxMyIgeD0iNDUxLjA2IiB5PSI0MTMuNzciLz48bGluZSBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiIHgxPSI0NTEuMDYiIHgyPSI2MzEuMDkxMyIgeTE9IjQ0MC4yNTgzIiB5Mj0iNDQwLjI1ODMiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIxMzQuODExNSIgeD0iNDczLjY2OTkiIHk9IjQzMi4zMDUyIj51bnVzZWQtYW5kLWNsb3NlZDwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI1Ny42MjExIiB4PSI0NTYuMDYiIHk9IjQ1Ni44NTk4Ij5jb3VudCA9IDA8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTYwLjAzMTMiIHg9IjQ1Ni4wNiIgeT0iNDcwLjk5MjciPnRyeV9hc3NvY2lhdGUoKSByZXR1cm5zIGZhbHNlPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9Ijk5LjI1MiIgeD0iNDU2LjA2IiB5PSI0ODUuMTI1NSI+am9pbigpIG5vdCBuZWVkZWQ8L3RleHQ+PC9nPjxnIGlkPSJqb2luZWQiPjxyZWN0IGZpbGw9IiNGMUYxRjEiIGhlaWdodD0iNzguODg2NyIgcng9IjEyLjUiIHJ5PSIxMi41IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiIHdpZHRoPSIxODAuMDMxMyIgeD0iMjYyLjA2IiB5PSI3NTUuNTQiLz48bGluZSBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiIHgxPSIyNjIuMDYiIHgyPSI0NDIuMDkxMyIgeTE9Ijc4Mi4wMjgzIiB5Mj0iNzgyLjAyODMiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI0Mi4yMDUxIiB4PSIzMzAuOTczMSIgeT0iNzc0LjA3NTIiPmpvaW5lZDwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI1Ny42MjExIiB4PSIyNjcuMDYiIHk9Ijc5OC42Mjk4Ij5jb3VudCA9IDA8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTYwLjAzMTMiIHg9IjI2Ny4wNiIgeT0iODEyLjc2MjciPnRyeV9hc3NvY2lhdGUoKSByZXR1cm5zIGZhbHNlPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9Ijk5LjI1MiIgeD0iMjY3LjA2IiB5PSI4MjYuODk1NSI+am9pbigpIG5vdCBuZWVkZWQ8L3RleHQ+PC9nPjxlbGxpcHNlIGN4PSI0NzEuMDgiIGN5PSIxNiIgZmlsbD0iIzIyMjIyMiIgcng9IjEwIiByeT0iMTAiIHN0eWxlPSJzdHJva2U6IzIyMjIyMjtzdHJva2Utd2lkdGg6MTsiLz48ZWxsaXBzZSBjeD0iNTQwLjA4IiBjeT0iOTIyLjQzIiBmaWxsPSJ0cmFuc3BhcmVudCIgcng9IjExIiByeT0iMTEiIHN0eWxlPSJzdHJva2U6IzIyMjIyMjtzdHJva2Utd2lkdGg6MTsiLz48ZWxsaXBzZSBjeD0iNTQwLjA4IiBjeT0iOTIyLjQzIiBmaWxsPSIjMjIyMjIyIiByeD0iNiIgcnk9IjYiIHN0eWxlPSJzdHJva2U6IzIyMjIyMjtzdHJva2Utd2lkdGg6MTsiLz48IS0tbGluayAqc3RhcnQqIHRvIHVudXNlZC0tPjxnIGlkPSJsaW5rXypzdGFydCpfdW51c2VkIj48cGF0aCBkPSJNNDcxLjA4LDI2LjI0IEM0NzEuMDgsMzkuNTYgNDcxLjA4LDU4LjkzIDQ3MS4wOCw4MC42OCAiIGZpbGw9InRyYW5zcGFyZW50IiBpZD0iKnN0YXJ0Ki10by11bnVzZWQiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MTsiLz48cG9seWdvbiBmaWxsPSIjMTgxODE4IiBwb2ludHM9IjQ3MS4wOCw4Ni42OCw0NzUuMDgsNzcuNjgsNDcxLjA4LDgxLjY4LDQ2Ny4wOCw3Ny42OCw0NzEuMDgsODYuNjgiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MTsiLz48L2c+PCEtLWxpbmsgdW51c2VkIHRvIG9wZW4tLT48ZyBpZD0ibGlua191bnVzZWRfb3BlbiI+PHBhdGggZD0iTTQyOC44NiwxNjYuMTcgQzQxOC45LDE3NS42OSA0MDguNDUsMTg2IDM5OS4wOCwxOTUuODggQzM4NC45OCwyMTAuNzUgMzc0LjAzNDYsMjIzLjIwMDQgMzYxLjQ1NDYsMjM4LjE0MDQgIiBmaWxsPSJ0cmFuc3BhcmVudCIgaWQ9InVudXNlZC10by1vcGVuIiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjE7Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIzNTcuNTksMjQyLjczLDM2Ni40NDY3LDIzOC40MjIsMzYwLjgxMDUsMjM4LjkwNTMsMzYwLjMyNzIsMjMzLjI2OTEsMzU3LjU5LDI0Mi43MyIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxOyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjkwLjA0NzkiIHg9IjQwMC4wOCIgeT0iMjA5LjQ0ODQiPnRyeV9hc3NvY2lhdGUoKTwvdGV4dD48L2c+PCEtLWxpbmsgdW51c2VkIHRvIHVudXNlZF9hbmRfY2xvc2VkLS0+PGcgaWQ9ImxpbmtfdW51c2VkX3VudXNlZF9hbmRfY2xvc2VkIj48cGF0aCBkPSJNNDg1Ljg3LDE2Ni4yIEM0ODkuMjEsMTc1LjggNDkyLjUxLDE4Ni4xNCA0OTUuMDgsMTk1Ljg4IEM1MTUuMSwyNzEuOTYgNTI4LjM0MjYsMzU3LjA5NTkgNTM1LjI5MjYsNDA3LjYzNTkgIiBmaWxsPSJ0cmFuc3BhcmVudCIgaWQ9InVudXNlZC10by11bnVzZWRfYW5kX2Nsb3NlZCIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxOyIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iNTM2LjExLDQxMy41OCw1MzguODQ2Niw0MDQuMTE5LDUzNS40Mjg4LDQwOC42MjY2LDUzMC45MjEyLDQwNS4yMDg4LDUzNi4xMSw0MTMuNTgiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MTsiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI0MC43MjY2IiB4PSI1MjIuNDQiIHk9IjI4Ny4zOTg0Ij5jbG9zZSgpPC90ZXh0PjwvZz48IS0tbGluayB1bnVzZWQgdG8gb3Blbl9hbmRfam9pbmluZy0tPjxnIGlkPSJsaW5rX3VudXNlZF9vcGVuX2FuZF9qb2luaW5nIj48cGF0aCBkPSJNMzczLjY2LDEzNC40MiBDMjk3LjI1LDE0NS4zMSAxOTQuNCwxNzIuOTcgMTM2LjA4LDI0Mi44OCBDOTYuMDQsMjkwLjg3IDk0LjU1NzIsMzYxLjQ2MTEgOTguNDI3Miw0MDcuNDgxMSAiIGZpbGw9InRyYW5zcGFyZW50IiBpZD0idW51c2VkLXRvLW9wZW5fYW5kX2pvaW5pbmciIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MTsiLz48cG9seWdvbiBmaWxsPSIjMTgxODE4IiBwb2ludHM9Ijk4LjkzLDQxMy40NiwxMDIuMTYxNyw0MDQuMTU2NSw5OC41MTEsNDA4LjQ3NzYsOTQuMTg5OSw0MDQuODI2OCw5OC45Myw0MTMuNDYiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MTsiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI3My45NjkyIiB4PSIxMzcuMDgiIHk9IjI3OS44OTg0Ij5qb2luLXNlbmRlcjwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI0NC4yNzQ5IiB4PSIxNTEuOTI3MiIgeT0iMjk1LjIwODkiPnN0YXJ0ZWQ8L3RleHQ+PC9nPjwhLS1saW5rIG9wZW4gdG8gY2xvc2VkLS0+PGcgaWQ9Imxpbmtfb3Blbl9jbG9zZWQiPjxwYXRoIGQ9Ik0zMjYuMDgsMzIyLjA3IEMzMjYuMDgsMzQ5LjQ0IDMyNi4wOCwzNzkuOTcgMzI2LjA4LDQwNy4zNiAiIGZpbGw9InRyYW5zcGFyZW50IiBpZD0ib3Blbi10by1jbG9zZWQiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MTsiLz48cG9seWdvbiBmaWxsPSIjMTgxODE4IiBwb2ludHM9IjMyNi4wOCw0MTMuMzYsMzMwLjA4LDQwNC4zNiwzMjYuMDgsNDA4LjM2LDMyMi4wOCw0MDQuMzYsMzI2LjA4LDQxMy4zNiIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxOyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjQwLjcyNjYiIHg9IjMyNy4wOCIgeT0iMzcyLjgzODQiPmNsb3NlKCk8L3RleHQ+PC9nPjwhLS1saW5rIG9wZW4gdG8gb3Blbl9hbmRfam9pbmluZy0tPjxnIGlkPSJsaW5rX29wZW5fb3Blbl9hbmRfam9pbmluZyI+PHBhdGggZD0iTTI3NS4xNCwzMjIuMDcgQzIzOS4xNywzNDkuNDQgMTk1LjkzNTUsMzgyLjMzNzYgMTU5LjkyNTUsNDA5LjcyNzYgIiBmaWxsPSJ0cmFuc3BhcmVudCIgaWQ9Im9wZW4tdG8tb3Blbl9hbmRfam9pbmluZyIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxOyIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iMTU1LjE1LDQxMy4zNiwxNjQuNzM0OSw0MTEuMDk1MSwxNTkuMTI5Niw0MTAuMzMzLDE1OS44OTE3LDQwNC43Mjc3LDE1NS4xNSw0MTMuMzYiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MTsiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI3My45NjkyIiB4PSIyMzUuOTYiIHk9IjM2NS4zMzg0Ij5qb2luLXNlbmRlcjwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI0NC4yNzQ5IiB4PSIyNTAuODA3MiIgeT0iMzgwLjY0ODkiPnN0YXJ0ZWQ8L3RleHQ+PC9nPjwhLS1saW5rIGNsb3NlZCB0byBjbG9zZWRfYW5kX2pvaW5pbmctLT48ZyBpZD0ibGlua19jbG9zZWRfY2xvc2VkX2FuZF9qb2luaW5nIj48cGF0aCBkPSJNMzIwLjI3LDQ5Mi45OSBDMzE4LjcsNTExLjkgMzE4LjcsNTM0Ljc5IDMyNC4wOCw1NTQuNjYgQzMyNi44NSw1NjQuODkgMzI4LjYzNDgsNTY5LjkxNyAzMzMuODg0OCw1NzkuMjc3ICIgZmlsbD0idHJhbnNwYXJlbnQiIGlkPSJjbG9zZWQtdG8tY2xvc2VkX2FuZF9qb2luaW5nIiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjE7Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIzMzYuODIsNTg0LjUxLDMzNS45MDU5LDU3NC43MDM3LDMzNC4zNzQsNTgwLjE0OTEsMzI4LjkyODUsNTc4LjYxNzIsMzM2LjgyLDU4NC41MSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxOyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjczLjk2OTIiIHg9IjMyNS4wOCIgeT0iNTM2LjIyODQiPmpvaW4tc2VuZGVyPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjQ0LjI3NDkiIHg9IjMzOS45MjcyIiB5PSI1NTEuNTM4OSI+c3RhcnRlZDwvdGV4dD48L2c+PCEtLWxpbmsgb3Blbl9hbmRfam9pbmluZyB0byBjbG9zZWRfYW5kX2pvaW5pbmctLT48ZyBpZD0ibGlua19vcGVuX2FuZF9qb2luaW5nX2Nsb3NlZF9hbmRfam9pbmluZyI+PHBhdGggZD0iTTE2My43Myw0OTIuOTYgQzIwNS44NSw1MjAuMzIgMjU3LjA1ODYsNTUzLjU4MTIgMjk5LjIxODYsNTgwLjk3MTIgIiBmaWxsPSJ0cmFuc3BhcmVudCIgaWQ9Im9wZW5fYW5kX2pvaW5pbmctdG8tY2xvc2VkX2FuZF9qb2luaW5nIiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjE7Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIzMDQuMjUsNTg0LjI0LDI5OC44ODIsNTc1Ljk4MjYsMzAwLjA1NzEsNTgxLjUxNiwyOTQuNTIzNyw1ODIuNjkxMiwzMDQuMjUsNTg0LjI0IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjE7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNDAuNzI2NiIgeD0iMjU4LjM2IiB5PSI1NDMuNzI4NCI+Y2xvc2UoKTwvdGV4dD48L2c+PCEtLWxpbmsgdW51c2VkX2FuZF9jbG9zZWQgdG8gY2xvc2VkX2FuZF9qb2luaW5nLS0+PGcgaWQ9ImxpbmtfdW51c2VkX2FuZF9jbG9zZWRfY2xvc2VkX2FuZF9qb2luaW5nIj48cGF0aCBkPSJNNDc1Ljk5LDQ5My4wNiBDNDYzLjE0LDUwMi4wMyA0NTAuMiw1MTIuMDggNDM5LjA4LDUyMi42NiBDNDE5LjgzLDU0MC45NSA0MDUuMjgzNSw1NTkuNjY1IDM5MS43ODM1LDU3OS40MzUgIiBmaWxsPSJ0cmFuc3BhcmVudCIgaWQ9InVudXNlZF9hbmRfY2xvc2VkLXRvLWNsb3NlZF9hbmRfam9pbmluZyIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxOyIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iMzg4LjQsNTg0LjM5LDM5Ni43Nzg2LDU3OS4yMTMyLDM5MS4yMTk2LDU4MC4yNjA5LDM5MC4xNzIsNTc0LjcwMTksMzg4LjQsNTg0LjM5IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjE7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNzMuOTY5MiIgeD0iNDQwLjA4IiB5PSI1MzYuMjI4NCI+am9pbi1zZW5kZXI8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNDQuMjc0OSIgeD0iNDU0LjkyNzIiIHk9IjU1MS41Mzg5Ij5zdGFydGVkPC90ZXh0PjwvZz48IS0tbGluayBjbG9zZWRfYW5kX2pvaW5pbmcgdG8gam9pbmVkLS0+PGcgaWQ9ImxpbmtfY2xvc2VkX2FuZF9qb2luaW5nX2pvaW5lZCI+PHBhdGggZD0iTTM1Ni44NCw2NjMuNzEgQzM1NS4zLDY3My40MSAzNTMuOSw2ODMuODMgMzUzLjA4LDY5My41NCBDMzUxLjM1LDcxMy44NyAzNTAuOTUxNSw3MzAuNjAwMSAzNTEuMDcxNSw3NDkuMjkwMSAiIGZpbGw9InRyYW5zcGFyZW50IiBpZD0iY2xvc2VkX2FuZF9qb2luaW5nLXRvLWpvaW5lZCIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxOyIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iMzUxLjExLDc1NS4yOSwzNTUuMDUyMSw3NDYuMjY0NSwzNTEuMDc3OSw3NTAuMjkwMSwzNDcuMDUyMyw3NDYuMzE1OSwzNTEuMTEsNzU1LjI5IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjE7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTAwLjQyNjMiIHg9IjM3NS4yNTU4IiB5PSI3MDcuMTA4NCI+Y291bnQgcmVhY2hlcyAwPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjE0Mi43Nzc4IiB4PSIzNTQuMDgiIHk9IjcyMi40MTg5Ij5qb2luLXNlbmRlciBjb21wbGV0ZXM8L3RleHQ+PC9nPjwhLS1saW5rIG9wZW5fYW5kX2pvaW5pbmcgdG8gam9pbmVkLS0+PGcgaWQ9Imxpbmtfb3Blbl9hbmRfam9pbmluZ19qb2luZWQiPjxwYXRoIGQ9Ik05NC44NCw0OTMuMDEgQzg2LjQ4LDUzNy43IDc5Ljg1LDYxMS42MyAxMTIuMDgsNjYzLjU0IEMxNDUuMjgsNzE3LjAzIDIwMi45NDQ3LDc0OC4wNTk5IDI1Ni4yMDQ3LDc2Ny41Mjk5ICIgZmlsbD0idHJhbnNwYXJlbnQiIGlkPSJvcGVuX2FuZF9qb2luaW5nLXRvLWpvaW5lZCIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxOyIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iMjYxLjg0LDc2OS41OSwyNTQuNzYwNSw3NjIuNzQzMSwyNTcuMTQzOSw3NjcuODczMywyNTIuMDEzNyw3NzAuMjU2OCwyNjEuODQsNzY5LjU5IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjE7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTAwLjQyNjMiIHg9IjEzNC4yNTU4IiB5PSI2MjEuNjY4NCI+Y291bnQgcmVhY2hlcyAwPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjE0Mi43Nzc4IiB4PSIxMTMuMDgiIHk9IjYzNi45Nzg5Ij5qb2luLXNlbmRlciBjb21wbGV0ZXM8L3RleHQ+PC9nPjwhLS1saW5rIGpvaW5lZCB0byAqZW5kKi0tPjxnIGlkPSJsaW5rX2pvaW5lZF8qZW5kKiI+PHBhdGggZD0iTTM0MC4yOCw4MzQuODYgQzMzNy44Nyw4NTAuODggMzM4LjY5LDg2OC42NCAzNDkuMDgsODgxLjQzIEMzNzIuMDQsOTA5LjcgNDg1LjE1OTksOTE4LjM1NTUgNTIyLjcxOTksOTIwLjUxNTUgIiBmaWxsPSJ0cmFuc3BhcmVudCIgaWQ9ImpvaW5lZC10by0qZW5kKiIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxOyIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iNTI4LjcxLDkyMC44Niw1MTkuOTU0NSw5MTYuMzQ5OSw1MjMuNzE4Miw5MjAuNTcyOSw1MTkuNDk1Miw5MjQuMzM2Nyw1MjguNzEsOTIwLjg2IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjE7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTYzLjY0ODkiIHg9IjM1MC4wOCIgeT0iODc3Ljk5ODQiPn5zaW1wbGVfY291bnRpbmdfc2NvcGUoKTwvdGV4dD48L2c+PCEtLWxpbmsgdW51c2VkX2FuZF9jbG9zZWQgdG8gKmVuZCotLT48ZyBpZD0ibGlua191bnVzZWRfYW5kX2Nsb3NlZF8qZW5kKiI+PHBhdGggZD0iTTUzOS45Niw0OTIuODUgQzUzOC41Nyw1NDUuNDggNTM2LjQ0LDY0Mi42MyA1MzcuMDgsNzI1LjU0IEM1MzcuNjIsNzk2LjYzIDUzOS4xNjAxLDg3Ni4yMTEyIDUzOS43NDAxLDkwNS4yMzEyICIgZmlsbD0idHJhbnNwYXJlbnQiIGlkPSJ1bnVzZWRfYW5kX2Nsb3NlZC10by0qZW5kKiIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxOyIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iNTM5Ljg2LDkxMS4yMyw1NDMuNjc5NCw5MDIuMTUxOSw1MzkuNzYwMSw5MDYuMjMxLDUzNS42ODEsOTAyLjMxMTcsNTM5Ljg2LDkxMS4yMyIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxOyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjE2My42NDg5IiB4PSI1MzguMDgiIHk9IjcxNC42MDg0Ij5+c2ltcGxlX2NvdW50aW5nX3Njb3BlKCk8L3RleHQ+PC9nPjwhLS1saW5rIHVudXNlZCB0byAqZW5kKi0tPjxnIGlkPSJsaW5rX3VudXNlZF8qZW5kKiI+PHBhdGggZD0iTTU2OC42LDE0NS4xIEM2NDEuMzEsMTY0LjU1IDcyOC4wOCwyMDMuOTcgNzI4LjA4LDI4MS4zMyBDNzI4LjA4LDI4MS4zMyA3MjguMDgsMjgxLjMzIDcyOC4wOCw3OTUuOTkgQzcyOC4wOCw4ODEuNzIgNTk3LjAyNjQsOTExLjQzNDQgNTU2LjkwNjQsOTE4LjYwNDQgIiBmaWxsPSJ0cmFuc3BhcmVudCIgaWQ9InVudXNlZC10by0qZW5kKiIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxOyIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iNTUxLDkxOS42Niw1NjAuNTYzMyw5MjIuMDE0Myw1NTUuOTIyLDkxOC43ODA0LDU1OS4xNTU5LDkxNC4xMzksNTUxLDkxOS42NiIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxOyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjE2My42NDg5IiB4PSI3MjkuMDgiIHk9IjU0My43Mjg0Ij5+c2ltcGxlX2NvdW50aW5nX3Njb3BlKCk8L3RleHQ+PC9nPjwhLS1TUkM9W2JQRERKaUdtMzhOdEZPS3JBcTJnREVrSHUyOEtMTDVoZUFZdWVwWFQ4MEh4M2lCNUUwZHZ3cS1RakRGUEpQX1Ytbm1kN2JQMjhWSktDelJtY05yYlI4TmtaM0p4aERla2gxLUM4SFRLdnN6VEdtc3o3NDJtSlBMUUJCcXUzcFg0NTc3b01pWVRvdVFTcU1RU1FaRkhtR3A0MnZjVndXSExydkUyVXBYRWFmOFZmTTNrZ2FRZFJjd1g0V0dJTEl6OWJ0Z1NaMFFld3pHZjhDR1F3eXBVcEczei1fZExNMnpUV2RoUlc3R3VGcTg4N0NLYnFrNE9kYU5CRURiMlBGR0V5TWFOdkpxZE5xSHlJemNKNFJCNEd3UDZrajB0RFR2c3R0V1B1bFNFZ3ppekt1YnUxX29RcExrRHFaUF9qQ05HeEY3azJWQnltSV91aThENklJX090OTZ5MV9DWmpBcXlQQ3Y4RFNnMnpCejhnYzc5SkkyMlpQTXpBNC1PTzdseDF4eExVM1phXzBBa3d2WG02aTNZZklNQXdYS1BaV05EQUJodVZjdkg4UVNGVll0NC1xdEt4Q0c5WWN6a0pCNnEwOHFqa1RBVExpVlViemZiX0dTMF0tLT48L2c+PC9zdmc+" /></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 join-sender 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
join-sender 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 join-sender 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">try_associate()</code> to return
<code class="sourceCode default">false</code>.</p>
<p>Associating work with a
<code class="sourceCode default">simple_counting_scope</code> can be
done through
<code class="sourceCode default">simple_counting_scope</code>’s token,
which provides three methods:
<code class="sourceCode default">wrap(sender auto&amp;&amp; s</code>),
<code class="sourceCode default">try_associate()</code>, and
<code class="sourceCode default">disassociate()</code>.</p>
<ul>
<li><code class="sourceCode default">wrap(sender auto&amp;&amp; s)</code>
takes in a sender and returns it unmodified.</li>
<li><code class="sourceCode default">try_associate()</code> attempts to
create a new association with the
<code class="sourceCode default">simple_counting_scope</code> and will
return <code class="sourceCode default">true</code> when successful, or
<code class="sourceCode default">false</code>. The requirements for
<code class="sourceCode default">try_associate()</code>’s success are
outlined below:
<ol type="1">
<li>While a scope is in the unused, open, or open-and-joining state,
calls to <code class="sourceCode default">token.try_associate()</code>
succeeds by incrementing the scope’s count of oustanding operations
before returning <code class="sourceCode default">true</code>.</li>
<li>While a scope is in the closed, unused-and-closed,
closed-and-joining, or joined state, calls to
<code class="sourceCode default">token.try_associate()</code> will
return <code class="sourceCode default">false</code> and <em>will
not</em> increment the scope’s count of outstanding operations.</li>
</ol></li>
</ul>
<p>When a token’s
<code class="sourceCode default">try_associate()</code> returns
<code class="sourceCode default">true</code>, the caller is responsible
for undoing the association by invoking
<code class="sourceCode default">disassociate()</code>, which will
decrement the scope’s count of oustanding operations.</p>
<ul>
<li>When a scope is in the open-and-joining or closed-and-joining state
and a call to <code class="sourceCode default">disassociate()</code>
undoes the final scope association, the scope moves to the joined state
and the outstanding join-sender completes.</li>
</ul>
<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 associated with
<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="cb33"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a>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="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="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="cb35"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb35-1"><a href="#cb35-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>
with <em><code class="sourceCode default">scope</code></em> set to
<code class="sourceCode default">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="cb36"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb36-1"><a href="#cb36-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">try_associate()</code> return
<code class="sourceCode default">false</code>.</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="cb37"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a>sender <span class="kw">auto</span> join<span class="op">()</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p>Returns a join-sender. When the join-sender 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
operations drops to zero. <code class="sourceCode default">o</code> will
complete synchronously inline if it happens to observe that the count of
outstanding operations 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
join-sender may be connected to in exchange for determinism; the
alternative would have the join-sender 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_scopetokenwrap"><span class="header-section-number">5.6.6</span> <code class="sourceCode default">simple_counting_scope::token::wrap</code><a href="#simple_counting_scopetokenwrap" 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><span class="kw">template</span> <span class="op">&lt;</span>sender Sender<span class="op">&gt;</span></span>
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a>Sender<span class="op">&amp;&amp;</span> wrap<span class="op">(</span>Sender<span class="op">&amp;&amp;</span> s<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p>Returns the argument unmodified.</p>
<h3 data-number="5.6.7" id="simple_counting_scopetokentry_associate"><span class="header-section-number">5.6.7</span> <code class="sourceCode default">simple_counting_scope::token::try_associate</code><a href="#simple_counting_scopetokentry_associate" 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">bool</span> try_associate<span class="op">()</span> <span class="kw">const</span>;</span></code></pre></div>
<p>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 and the method returns
<code class="sourceCode default">true</code> if the scope is observed to
be in the unused, open, or open-and-joining state; otherwise the scope’s
state is left unchanged and the method returns
<code class="sourceCode default">false</code>.</p>
<h3 data-number="5.6.8" id="simple_counting_scopetokendisassociate"><span class="header-section-number">5.6.8</span> <code class="sourceCode default">simple_counting_scope::token::disassociate</code><a href="#simple_counting_scopetokendisassociate" 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> disassociate<span class="op">()</span> <span class="kw">const</span>;</span></code></pre></div>
<p>Decrements the associated scope’s count of outstanding operations
and, when the scope is in the open-and-joining or closed-and-joing
state, moves the scope to the joined state and signals the outstanding
join-sender to complete.</p>
<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="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">class</span> counting_scope <span class="op">{</span></span>
<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> token <span class="op">{</span></span>
<span id="cb41-3"><a href="#cb41-3" 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="cb41-4"><a href="#cb41-4" aria-hidden="true" tabindex="-1"></a>        sender <span class="kw">auto</span> wrap<span class="op">(</span>Sender<span class="op">&amp;&amp;</span> snd<span class="op">)</span>;</span>
<span id="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-6"><a href="#cb41-6" aria-hidden="true" tabindex="-1"></a>        <span class="dt">bool</span> try_associate<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb41-7"><a href="#cb41-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-8"><a href="#cb41-8" aria-hidden="true" tabindex="-1"></a>        <span class="dt">void</span> disassociate<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb41-9"><a href="#cb41-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-10"><a href="#cb41-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">private</span><span class="op">:</span></span>
<span id="cb41-11"><a href="#cb41-11" aria-hidden="true" tabindex="-1"></a>        counting_scope<span class="op">*</span> scope; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb41-12"><a href="#cb41-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb41-13"><a href="#cb41-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-14"><a href="#cb41-14" aria-hidden="true" tabindex="-1"></a>    counting_scope<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb41-15"><a href="#cb41-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">~</span>counting_scope<span class="op">()</span>;</span>
<span id="cb41-16"><a href="#cb41-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-17"><a href="#cb41-17" aria-hidden="true" tabindex="-1"></a>    <span class="co">// counting_scope is immovable and uncopyable</span></span>
<span id="cb41-18"><a href="#cb41-18" 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="cb41-19"><a href="#cb41-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-20"><a href="#cb41-20" aria-hidden="true" tabindex="-1"></a>    token get_token<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb41-21"><a href="#cb41-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-22"><a href="#cb41-22" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> close<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb41-23"><a href="#cb41-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-24"><a href="#cb41-24" 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="cb41-25"><a href="#cb41-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-26"><a href="#cb41-26" aria-hidden="true" tabindex="-1"></a>    sender <span class="kw">auto</span> join<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb41-27"><a href="#cb41-27" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>A <code class="sourceCode default">counting_scope</code> behaves like
a <code class="sourceCode default">simple_counting_scope</code>
augmented with a stop source; the
<code class="sourceCode default">wrap</code> method on a
<code class="sourceCode default">counting_scope</code>’s
<code class="sourceCode default">token</code> returns a sender that,
when connected and started, produces an
<em><code class="sourceCode default">operation-state</code></em> that
receives stop requests from both its receiver and from the
<code class="sourceCode default">counting_scope</code>. 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="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">class</span> counting_scope <span class="op">{</span></span>
<span id="cb42-2"><a href="#cb42-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> token <span class="op">{</span></span>
<span id="cb42-3"><a href="#cb42-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="cb42-4"><a href="#cb42-4" aria-hidden="true" tabindex="-1"></a>        sender <span class="kw">auto</span> wrap<span class="op">(</span>S<span class="op">&amp;&amp;</span> snd<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb42-5"><a href="#cb42-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="cb42-6"><a href="#cb42-6" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> <em>stop_when</em><span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>S<span class="op">&gt;(</span>snd<span class="op">)</span>, scope_<span class="op">-&gt;</span>source_<span class="op">.</span>get_token<span class="op">())</span>;</span>
<span id="cb42-7"><a href="#cb42-7" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb42-8"><a href="#cb42-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb42-9"><a href="#cb42-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">private</span><span class="op">:</span></span>
<span id="cb42-10"><a href="#cb42-10" aria-hidden="true" tabindex="-1"></a>        <span class="kw">friend</span> counting_scope;</span>
<span id="cb42-11"><a href="#cb42-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb42-12"><a href="#cb42-12" 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="cb42-13"><a href="#cb42-13" 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="cb42-14"><a href="#cb42-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb42-15"><a href="#cb42-15" aria-hidden="true" tabindex="-1"></a>        counting_scope<span class="op">*</span> scope_;</span>
<span id="cb42-16"><a href="#cb42-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb42-17"><a href="#cb42-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb42-18"><a href="#cb42-18" aria-hidden="true" tabindex="-1"></a>    token get_token<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span> <span class="cf">return</span> token<span class="op">{</span><span class="kw">this</span><span class="op">}</span>; <span class="op">}</span></span>
<span id="cb42-19"><a href="#cb42-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb42-20"><a href="#cb42-20" 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 class="cf">return</span> scope_<span class="op">.</span>close<span class="op">()</span>; <span class="op">}</span></span>
<span id="cb42-21"><a href="#cb42-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb42-22"><a href="#cb42-22" 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> source_<span class="op">.</span>request_stop<span class="op">()</span>; <span class="op">}</span></span>
<span id="cb42-23"><a href="#cb42-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb42-24"><a href="#cb42-24" 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 class="cf">return</span> scope_<span class="op">.</span>join<span class="op">()</span>; <span class="op">}</span></span>
<span id="cb42-25"><a href="#cb42-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb42-26"><a href="#cb42-26" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb42-27"><a href="#cb42-27" aria-hidden="true" tabindex="-1"></a>    simple_counting_scope scope_;</span>
<span id="cb42-28"><a href="#cb42-28" aria-hidden="true" tabindex="-1"></a>    inplace_stop_source source_;</span>
<span id="cb42-29"><a href="#cb42-29" 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::wrap()</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="cb43"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb43-1"><a href="#cb43-1" aria-hidden="true" tabindex="-1"></a>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="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="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="cb45"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb45-1"><a href="#cb45-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> with
<em><code class="sourceCode default">scope</code></em> set to
<code class="sourceCode default">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="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="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">try_associate()</code> return
disengaged associations.</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="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="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
associated with 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="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">struct</span> <em>join-sender</em>; <span class="co">// <em>exposition-only</em></span></span>
<span id="cb48-2"><a href="#cb48-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb48-3"><a href="#cb48-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 join-sender that behaves the same as the result of
<code class="sourceCode default">simple_counting_scope::join()</code>.
Connecting and starting the join-sender moves the scope to the
open-and-joining or closed-and-joining state; the join-sender 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_scopetokenwrap"><span class="header-section-number">5.7.7</span>
<code class="sourceCode default">counting_scope::token::wrap</code><a href="#counting_scopetokenwrap" class="self-link"></a></h3>
<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<span class="op">&gt;</span></span>
<span id="cb49-2"><a href="#cb49-2" aria-hidden="true" tabindex="-1"></a>sender <span class="kw">auto</span> wrap<span class="op">(</span>Sender<span class="op">&amp;&amp;</span> snd<span class="op">)</span>;</span></code></pre></div>
<p>Returns a sender, <code class="sourceCode default">osnd</code>, that
behaves in all ways the same as the input sender,
<code class="sourceCode default">snd</code>, except that, when
<code class="sourceCode default">osnd</code> is connected to a receiver,
the resulting
<em><code class="sourceCode default">operation-state</code></em>
receives stop requests from <em>both</em> the connected receiver
<em>and</em> the stop source in the token’s
<code class="sourceCode default">counting_scope</code>.</p>
<h3 data-number="5.7.8" id="counting_scopetokentry_associate"><span class="header-section-number">5.7.8</span> <code class="sourceCode default">counting_scope::token::try_associate</code><a href="#counting_scopetokentry_associate" class="self-link"></a></h3>
<div class="sourceCode" id="cb50"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb50-1"><a href="#cb50-1" aria-hidden="true" tabindex="-1"></a><span class="dt">bool</span> try_associate<span class="op">()</span> <span class="kw">const</span>;</span></code></pre></div>
<p>Returns <code class="sourceCode default">true</code> if the token’s
scope is open, and <code class="sourceCode default">false</code> if it’s
closed. <code class="sourceCode default">try_associate()</code> behaves
as if its <code class="sourceCode default">counting_scope</code> owns a
<code class="sourceCode default">simple_counting_scope</code>,
<code class="sourceCode default">scope</code>, and the result is
equivalent to the result of invoking <code class="sourceCode default">scope.get_token().try_associate()</code>.</p>
<h2 data-number="5.8" id="when-to-use-counting_scope-vs-p3296r2s-let_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="P3296R2">[<a href="#ref-P3296R2" role="doc-biblioref">P3296R2</a>]</span>’s
<code class="sourceCode default">let_async_scope</code><a href="#when-to-use-counting_scope-vs-p3296r2s-let_async_scope" class="self-link"></a></h2>
<p>Although <code class="sourceCode default">counting_scope</code> and
<code class="sourceCode default">let_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_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_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_async_scope</code> will manage
the scope for you, ensuring that the managed scope is always joined
before <code class="sourceCode default">let_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_async_scope</code> is intended to
live only until the sender completes. This also means that
<code class="sourceCode default">let_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="cb51"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb51-1"><a href="#cb51-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="cb51-2"><a href="#cb51-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>
<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="cb52"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb52-1"><a href="#cb52-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, async_scope_token Token<span class="op">&gt;</span></span>
<span id="cb52-2"><a href="#cb52-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>.
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</code>, which would
look like this:</p>
<div class="sourceCode" id="cb53"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb53-1"><a href="#cb53-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>sender Sender, async_task_pool_ref Ref<span class="op">&gt;</span></span>
<span id="cb53-2"><a href="#cb53-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="async_scope_token"><span class="header-section-number">7.1</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 associating
senders with scopes. It is primarily useful for constraining the
arguments to scope-related algorithms like the proposed
<code class="sourceCode default">nest()</code>,
<code class="sourceCode default">spawn()</code>, and
<code class="sourceCode default">spawn_future()</code> to give useful
error messages for invalid invocations.</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.2" id="nest"><span class="header-section-number">7.2</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.</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.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 nested in 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, 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="header-version-synopsis-version.syn"><span class="header-section-number">8.1</span> Header
<code class="sourceCode default">&lt;version&gt;</code> synopsis
<span>17.3.2
<a href="https://wg21.link/version.syn">[version.syn]</a></span><a href="#header-version-synopsis-version.syn" class="self-link"></a></h2>
<p>To the <code class="sourceCode default">&lt;version&gt;</code>
synopsis <span>17.3.2
<a href="https://wg21.link/version.syn">[version.syn]</a></span>, add
the following:</p>
<div class="sourceCode" id="cb54"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb54-1"><a href="#cb54-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#define __cpp_lib_coroutine                         </span><span class="dv">201902</span><span class="bu">L</span><span class="pp"> </span><span class="co">// also in &lt;coroutine&gt;</span></span>
<span id="cb54-2"><a href="#cb54-2" aria-hidden="true" tabindex="-1"></a><span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">#define __cpp_lib_counting_scope                    2025XXL // also in &lt;execution&gt;</code></span></ins></span></span>
<span id="cb54-3"><a href="#cb54-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#define __cpp_lib_debugging                         </span><span class="dv">202403</span><span class="bu">L</span><span class="pp"> </span><span class="co">// freestanding, also in &lt;debugging&gt;</span></span></code></pre></div>
<h2 data-number="8.2" id="header-execution-synopsis-execution.syn"><span class="header-section-number">8.2</span> Header
<code class="sourceCode default">&lt;execution&gt;</code> synopsis
<span>33.4
<a href="https://wg21.link/execution.syn">[execution.syn]</a></span><a href="#header-execution-synopsis-execution.syn" class="self-link"></a></h2>
<p>To the <code class="sourceCode default">&lt;execution&gt;</code>
synopsis <span>33.4
<a href="https://wg21.link/execution.syn">[execution.syn]</a></span>,
make the following additions:</p>
<blockquote>
<div class="sourceCode" id="cb55"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb55-1"><a href="#cb55-1" aria-hidden="true" tabindex="-1"></a>...</span>
<span id="cb55-2"><a href="#cb55-2" aria-hidden="true" tabindex="-1"></a>namespace std::execution {</span>
<span id="cb55-3"><a href="#cb55-3" aria-hidden="true" tabindex="-1"></a>  ...</span>
<span id="cb55-4"><a href="#cb55-4" aria-hidden="true" tabindex="-1"></a>  struct stopped_as_error_t { unspecified };</span></code></pre></div>
</blockquote>
<div class="add" style="color: #006e28">

<blockquote>
<div class="sourceCode" id="cb56"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb56-1"><a href="#cb56-1" aria-hidden="true" tabindex="-1"></a>  struct nest_t { <em>unspecified</em> };</span>
<span id="cb56-2"><a href="#cb56-2" aria-hidden="true" tabindex="-1"></a>  struct spawn_future_t { <em>unspecified</em> };</span></code></pre></div>
</blockquote>

</div>
<blockquote>
<div class="sourceCode" id="cb57"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb57-1"><a href="#cb57-1" aria-hidden="true" tabindex="-1"></a>  inline constexpr starts_on_t starts_on{};</span>
<span id="cb57-2"><a href="#cb57-2" aria-hidden="true" tabindex="-1"></a>  ...</span>
<span id="cb57-3"><a href="#cb57-3" aria-hidden="true" tabindex="-1"></a>  inline constexpr stopped_as_error_t stopped_as_error{};</span></code></pre></div>
</blockquote>
<div class="add" style="color: #006e28">

<blockquote>
<div class="sourceCode" id="cb58"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb58-1"><a href="#cb58-1" aria-hidden="true" tabindex="-1"></a>  inline constexpr nest_t nest{};</span>
<span id="cb58-2"><a href="#cb58-2" aria-hidden="true" tabindex="-1"></a>  inline constexpr spawn_future_t spawn_future{};</span></code></pre></div>
</blockquote>

</div>
<blockquote>
<div class="sourceCode" id="cb59"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb59-1"><a href="#cb59-1" aria-hidden="true" tabindex="-1"></a>  ...</span>
<span id="cb59-2"><a href="#cb59-2" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb59-3"><a href="#cb59-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb59-4"><a href="#cb59-4" aria-hidden="true" tabindex="-1"></a>namespace std::this_thread {</span>
<span id="cb59-5"><a href="#cb59-5" aria-hidden="true" tabindex="-1"></a>  // [exec.consumers], consumers</span>
<span id="cb59-6"><a href="#cb59-6" aria-hidden="true" tabindex="-1"></a>  struct sync_wait_t { unspecified };</span>
<span id="cb59-7"><a href="#cb59-7" aria-hidden="true" tabindex="-1"></a>  struct sync_wait_with_variant_t { unspecified };</span>
<span id="cb59-8"><a href="#cb59-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb59-9"><a href="#cb59-9" aria-hidden="true" tabindex="-1"></a>  inline constexpr sync_wait_t sync_wait{};</span>
<span id="cb59-10"><a href="#cb59-10" aria-hidden="true" tabindex="-1"></a>  inline constexpr sync_wait_with_variant_t sync_wait_with_variant{};</span>
<span id="cb59-11"><a href="#cb59-11" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb59-12"><a href="#cb59-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb59-13"><a href="#cb59-13" aria-hidden="true" tabindex="-1"></a>namespace std::execution {</span></code></pre></div>
</blockquote>
<div class="add" style="color: #006e28">

<blockquote>
<div class="sourceCode" id="cb60"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb60-1"><a href="#cb60-1" aria-hidden="true" tabindex="-1"></a>  // [exec.consumers], consumers</span>
<span id="cb60-2"><a href="#cb60-2" aria-hidden="true" tabindex="-1"></a>  struct spawn_t { <em>unspecified</em> };</span>
<span id="cb60-3"><a href="#cb60-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb60-4"><a href="#cb60-4" aria-hidden="true" tabindex="-1"></a>  inline constexpr spawn_t spawn{};</span></code></pre></div>
</blockquote>

</div>
<blockquote>
<div class="sourceCode" id="cb61"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb61-1"><a href="#cb61-1" aria-hidden="true" tabindex="-1"></a>  // [exec.as.awaitable]</span>
<span id="cb61-2"><a href="#cb61-2" aria-hidden="true" tabindex="-1"></a>  ...</span>
<span id="cb61-3"><a href="#cb61-3" aria-hidden="true" tabindex="-1"></a>    struct with_awaitable_senders;</span></code></pre></div>
</blockquote>
<div class="add" style="color: #006e28">

<blockquote>
<div class="sourceCode" id="cb62"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb62-1"><a href="#cb62-1" aria-hidden="true" tabindex="-1"></a>  // [exec.scope]</span>
<span id="cb62-2"><a href="#cb62-2" aria-hidden="true" tabindex="-1"></a>  // [exec.scope.concepts], scope concepts</span>
<span id="cb62-3"><a href="#cb62-3" aria-hidden="true" tabindex="-1"></a>  template &lt;class Token&gt;</span>
<span id="cb62-4"><a href="#cb62-4" aria-hidden="true" tabindex="-1"></a>    concept async_scope_token = <em>see below</em>;</span>
<span id="cb62-5"><a href="#cb62-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb62-6"><a href="#cb62-6" aria-hidden="true" tabindex="-1"></a>  // [exec.scope.simple.counting]</span>
<span id="cb62-7"><a href="#cb62-7" aria-hidden="true" tabindex="-1"></a>  class simple_counting_scope;</span>
<span id="cb62-8"><a href="#cb62-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb62-9"><a href="#cb62-9" aria-hidden="true" tabindex="-1"></a>  // [exec.scope.counting]</span>
<span id="cb62-10"><a href="#cb62-10" aria-hidden="true" tabindex="-1"></a>  class counting_scope;</span></code></pre></div>
</blockquote>

</div>
<blockquote>
<div class="sourceCode" id="cb63"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb63-1"><a href="#cb63-1" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
</blockquote>
<h2 data-number="8.3" id="executionnest-1"><span class="header-section-number">8.3</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 at the end of <span>33.9.12
<a href="https://wg21.link/exec.adapt">[exec.adapt]</a></span>:</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>
Let <em><code class="sourceCode default">nest-data</code></em> be the
following exposition-only class template:</p>
<div class="sourceCode" id="cb64"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb64-1"><a href="#cb64-1" aria-hidden="true" tabindex="-1"></a>namespace std::execution {</span>
<span id="cb64-2"><a href="#cb64-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb64-3"><a href="#cb64-3" aria-hidden="true" tabindex="-1"></a>template &lt;async_scope_token Token, sender Sender&gt;</span>
<span id="cb64-4"><a href="#cb64-4" aria-hidden="true" tabindex="-1"></a>struct <em>nest-data</em> {</span>
<span id="cb64-5"><a href="#cb64-5" aria-hidden="true" tabindex="-1"></a>    using <em>wrap-sender</em> = remove_cvref_t&lt;decltype(declval&lt;Token&amp;&gt;().wrap(declval&lt;Sender&gt;()))&gt;;</span>
<span id="cb64-6"><a href="#cb64-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb64-7"><a href="#cb64-7" aria-hidden="true" tabindex="-1"></a>    optional&lt;<em>wrap-sender</em>&gt; sndr;</span>
<span id="cb64-8"><a href="#cb64-8" aria-hidden="true" tabindex="-1"></a>    Token token;</span>
<span id="cb64-9"><a href="#cb64-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb64-10"><a href="#cb64-10" aria-hidden="true" tabindex="-1"></a>    <em>nest-data</em>(Token t, Sender&amp;&amp; s)</span>
<span id="cb64-11"><a href="#cb64-11" aria-hidden="true" tabindex="-1"></a>        : sndr(t.wrap(std::forward&lt;Sender&gt;(s))),</span>
<span id="cb64-12"><a href="#cb64-12" aria-hidden="true" tabindex="-1"></a>          token(t) {</span>
<span id="cb64-13"><a href="#cb64-13" aria-hidden="true" tabindex="-1"></a>        if (!token.try_associate())</span>
<span id="cb64-14"><a href="#cb64-14" aria-hidden="true" tabindex="-1"></a>            sndr.reset();</span>
<span id="cb64-15"><a href="#cb64-15" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb64-16"><a href="#cb64-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb64-17"><a href="#cb64-17" aria-hidden="true" tabindex="-1"></a>    <em>nest-data</em>(const <em>nest-data</em>&amp; other)</span>
<span id="cb64-18"><a href="#cb64-18" aria-hidden="true" tabindex="-1"></a>        requires copy_constructible&lt;<em>wrap-sender</em>&gt;</span>
<span id="cb64-19"><a href="#cb64-19" aria-hidden="true" tabindex="-1"></a>        : token(other.token) {</span>
<span id="cb64-20"><a href="#cb64-20" aria-hidden="true" tabindex="-1"></a>        if (other.sndr.has_value() &amp;&amp; token.try_associate()) {</span>
<span id="cb64-21"><a href="#cb64-21" aria-hidden="true" tabindex="-1"></a>            try {</span>
<span id="cb64-22"><a href="#cb64-22" aria-hidden="true" tabindex="-1"></a>                sndr.emplace(*other.sndr);</span>
<span id="cb64-23"><a href="#cb64-23" aria-hidden="true" tabindex="-1"></a>            }</span>
<span id="cb64-24"><a href="#cb64-24" aria-hidden="true" tabindex="-1"></a>            catch (...) {</span>
<span id="cb64-25"><a href="#cb64-25" aria-hidden="true" tabindex="-1"></a>                token.disassociate();</span>
<span id="cb64-26"><a href="#cb64-26" aria-hidden="true" tabindex="-1"></a>                throw;</span>
<span id="cb64-27"><a href="#cb64-27" aria-hidden="true" tabindex="-1"></a>            }</span>
<span id="cb64-28"><a href="#cb64-28" aria-hidden="true" tabindex="-1"></a>        }</span>
<span id="cb64-29"><a href="#cb64-29" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb64-30"><a href="#cb64-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb64-31"><a href="#cb64-31" aria-hidden="true" tabindex="-1"></a>    // alternative copy-constructor implementation:</span>
<span id="cb64-32"><a href="#cb64-32" aria-hidden="true" tabindex="-1"></a>    <em>nest-data</em>(const <em>nest-data</em>&amp; other)</span>
<span id="cb64-33"><a href="#cb64-33" aria-hidden="true" tabindex="-1"></a>        requires copy_constructible&lt;<em>wrap-sender</em>&gt;</span>
<span id="cb64-34"><a href="#cb64-34" aria-hidden="true" tabindex="-1"></a>        : sndr(other.sndr),</span>
<span id="cb64-35"><a href="#cb64-35" aria-hidden="true" tabindex="-1"></a>          token(other.token) {</span>
<span id="cb64-36"><a href="#cb64-36" aria-hidden="true" tabindex="-1"></a>        if (other.sndr.has_value() &amp;&amp; !token.try_associate())</span>
<span id="cb64-37"><a href="#cb64-37" aria-hidden="true" tabindex="-1"></a>            sndr.reset();</span>
<span id="cb64-38"><a href="#cb64-38" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb64-39"><a href="#cb64-39" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb64-40"><a href="#cb64-40" aria-hidden="true" tabindex="-1"></a>    <em>nest-data</em>(<em>nest-data</em>&amp;&amp; other) noexcept(is_nothrow_move_constructible_v&lt;<em>wrap-sender</em>&gt;)</span>
<span id="cb64-41"><a href="#cb64-41" aria-hidden="true" tabindex="-1"></a>        : sndr(std::move(other).sndr),</span>
<span id="cb64-42"><a href="#cb64-42" aria-hidden="true" tabindex="-1"></a>          token(std::move(other).token) {</span>
<span id="cb64-43"><a href="#cb64-43" aria-hidden="true" tabindex="-1"></a>        other.sndr.reset();</span>
<span id="cb64-44"><a href="#cb64-44" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb64-45"><a href="#cb64-45" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb64-46"><a href="#cb64-46" aria-hidden="true" tabindex="-1"></a>    ~<em>nest-data</em>() {</span>
<span id="cb64-47"><a href="#cb64-47" aria-hidden="true" tabindex="-1"></a>        if (sndr.has_value()) {</span>
<span id="cb64-48"><a href="#cb64-48" aria-hidden="true" tabindex="-1"></a>            sndr.reset();</span>
<span id="cb64-49"><a href="#cb64-49" aria-hidden="true" tabindex="-1"></a>            token.disassociate();</span>
<span id="cb64-50"><a href="#cb64-50" aria-hidden="true" tabindex="-1"></a>        }</span>
<span id="cb64-51"><a href="#cb64-51" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb64-52"><a href="#cb64-52" aria-hidden="true" tabindex="-1"></a>};</span>
<span id="cb64-53"><a href="#cb64-53" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb64-54"><a href="#cb64-54" aria-hidden="true" tabindex="-1"></a>template &lt;async_scope_token Token, sender Sender&gt;</span>
<span id="cb64-55"><a href="#cb64-55" aria-hidden="true" tabindex="-1"></a><em>nest-data</em>(Token, Sender&amp;&amp;) -&gt; <em>nest-data</em>&lt;Token, Sender&gt;;</span>
<span id="cb64-56"><a href="#cb64-56" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb64-57"><a href="#cb64-57" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
The name <code class="sourceCode default">nest</code> denotes a pipeable
sender adaptor object. For subexpressions
<code class="sourceCode default">sndr</code> and
<code class="sourceCode default">token</code>, if
<code class="sourceCode default">decltype((sndr))</code> does not
satisfy <code class="sourceCode default">sender</code>, or
<code class="sourceCode default">decltype((token))</code> does not
satisfy <code class="sourceCode default">async_scope_token</code>, then
<code class="sourceCode default">nest(sndr, token)</code> is
ill-formed.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
Otherwise, the expression
<code class="sourceCode default">nest(sndr, token)</code> is
expression-equivalent to:</p>
<div class="sourceCode" id="cb65"><pre class="sourceCode default default"><code class="sourceCode default"><span id="cb65-1"><a href="#cb65-1" aria-hidden="true" tabindex="-1"></a>transform_sender(<em>get-domain-early</em>(sndr), <em>make-sender</em>(nest, <em>nest-data</em>{token, sndr}))</span></code></pre></div>
<p>except that <code class="sourceCode default">sndr</code> is evaluated
only once.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
The exposition-only class template
<em><code class="sourceCode default">impls-for</code></em> (<span>33.9.1
<a href="https://wg21.link/exec.snd.general">[exec.snd.general]</a></span>)
is specialized for <code class="sourceCode default">nest_t</code> as
follows:</p>
<div class="sourceCode" id="cb66"><pre class="sourceCode default default"><code class="sourceCode default"><span id="cb66-1"><a href="#cb66-1" aria-hidden="true" tabindex="-1"></a>namespace std::execution {</span>
<span id="cb66-2"><a href="#cb66-2" aria-hidden="true" tabindex="-1"></a>    template &lt;&gt;</span>
<span id="cb66-3"><a href="#cb66-3" aria-hidden="true" tabindex="-1"></a>    struct <em>impls-for</em>&lt;nest_t&gt; : <em>default-impls</em> {</span>
<span id="cb66-4"><a href="#cb66-4" aria-hidden="true" tabindex="-1"></a>        static constexpr auto <em>get-state</em> = <em>see below</em>;</span>
<span id="cb66-5"><a href="#cb66-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb66-6"><a href="#cb66-6" aria-hidden="true" tabindex="-1"></a>        static constexpr auto <em>start</em> = <em>see below</em>;</span>
<span id="cb66-7"><a href="#cb66-7" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb66-8"><a href="#cb66-8" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
The member <code class="sourceCode default"><em>impls-for</em>&lt;nest_t&gt;::<em>get-state</em></code>
is initialized with a callable object equivalent to the following
lambda:</p>
<div class="sourceCode" id="cb67"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb67-1"><a href="#cb67-1" aria-hidden="true" tabindex="-1"></a>[]&lt;class Sndr, class Rcvr&gt;(Sndr&amp;&amp; sndr, Rcvr&amp; rcvr) {</span>
<span id="cb67-2"><a href="#cb67-2" aria-hidden="true" tabindex="-1"></a>    auto&amp; [_, data, ...child] = sndr;</span>
<span id="cb67-3"><a href="#cb67-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb67-4"><a href="#cb67-4" aria-hidden="true" tabindex="-1"></a>    using scope_token = decltype(data.token);</span>
<span id="cb67-5"><a href="#cb67-5" aria-hidden="true" tabindex="-1"></a>    using op_t = decltype(connect(std::forward_like&lt;Sndr&gt;(data.sndr.value()), rcvr));</span>
<span id="cb67-6"><a href="#cb67-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb67-7"><a href="#cb67-7" aria-hidden="true" tabindex="-1"></a>    static_assert(sizeof...(child) == 0);</span>
<span id="cb67-8"><a href="#cb67-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb67-9"><a href="#cb67-9" aria-hidden="true" tabindex="-1"></a>    struct op_state {</span>
<span id="cb67-10"><a href="#cb67-10" aria-hidden="true" tabindex="-1"></a>        bool associated = false;</span>
<span id="cb67-11"><a href="#cb67-11" aria-hidden="true" tabindex="-1"></a>        scope_token token;</span>
<span id="cb67-12"><a href="#cb67-12" aria-hidden="true" tabindex="-1"></a>        union {</span>
<span id="cb67-13"><a href="#cb67-13" aria-hidden="true" tabindex="-1"></a>            Rcvr* rcvr;</span>
<span id="cb67-14"><a href="#cb67-14" aria-hidden="true" tabindex="-1"></a>            op_t op;</span>
<span id="cb67-15"><a href="#cb67-15" aria-hidden="true" tabindex="-1"></a>        };</span>
<span id="cb67-16"><a href="#cb67-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb67-17"><a href="#cb67-17" aria-hidden="true" tabindex="-1"></a>        op_state(scope_token token, Rcvr&amp; r) noexcept</span>
<span id="cb67-18"><a href="#cb67-18" aria-hidden="true" tabindex="-1"></a>            : token(std::move(token)),</span>
<span id="cb67-19"><a href="#cb67-19" aria-hidden="true" tabindex="-1"></a>              rcvr(addressof(r)) {}</span>
<span id="cb67-20"><a href="#cb67-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb67-21"><a href="#cb67-21" aria-hidden="true" tabindex="-1"></a>        op_state(scope_token token, <em>wrap-sender</em>&amp;&amp; sndr, Rcvr&amp; r)</span>
<span id="cb67-22"><a href="#cb67-22" aria-hidden="true" tabindex="-1"></a>            : associated(true),</span>
<span id="cb67-23"><a href="#cb67-23" aria-hidden="true" tabindex="-1"></a>              token(std::move(token)),</span>
<span id="cb67-24"><a href="#cb67-24" aria-hidden="true" tabindex="-1"></a>              op(connect(std::move(sndr), std::move(r))) {}</span>
<span id="cb67-25"><a href="#cb67-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb67-26"><a href="#cb67-26" aria-hidden="true" tabindex="-1"></a>        op_state(scope_token token, const <em>wrap-sender</em>&amp; sndr, Rcvr&amp; r)</span>
<span id="cb67-27"><a href="#cb67-27" aria-hidden="true" tabindex="-1"></a>            : associated(token.try_associate()),</span>
<span id="cb67-28"><a href="#cb67-28" aria-hidden="true" tabindex="-1"></a>              token(std::move(token)),</span>
<span id="cb67-29"><a href="#cb67-29" aria-hidden="true" tabindex="-1"></a>              rcvr(addressof(r)) {</span>
<span id="cb67-30"><a href="#cb67-30" aria-hidden="true" tabindex="-1"></a>            if (associated)</span>
<span id="cb67-31"><a href="#cb67-31" aria-hidden="true" tabindex="-1"></a>                ::new (<em>voidify</em>(op)) op_t(connect(sndr, std::move(r)));</span>
<span id="cb67-32"><a href="#cb67-32" aria-hidden="true" tabindex="-1"></a>        }</span>
<span id="cb67-33"><a href="#cb67-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb67-34"><a href="#cb67-34" aria-hidden="true" tabindex="-1"></a>        op_state(op_state&amp;&amp;) = delete;</span>
<span id="cb67-35"><a href="#cb67-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb67-36"><a href="#cb67-36" aria-hidden="true" tabindex="-1"></a>        ~op_state() {</span>
<span id="cb67-37"><a href="#cb67-37" aria-hidden="true" tabindex="-1"></a>            if (associated) {</span>
<span id="cb67-38"><a href="#cb67-38" aria-hidden="true" tabindex="-1"></a>                token.disassociate();</span>
<span id="cb67-39"><a href="#cb67-39" aria-hidden="true" tabindex="-1"></a>                op.~op_t();</span>
<span id="cb67-40"><a href="#cb67-40" aria-hidden="true" tabindex="-1"></a>            }</span>
<span id="cb67-41"><a href="#cb67-41" aria-hidden="true" tabindex="-1"></a>        }</span>
<span id="cb67-42"><a href="#cb67-42" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb67-43"><a href="#cb67-43" aria-hidden="true" tabindex="-1"></a>        void start() noexcept {</span>
<span id="cb67-44"><a href="#cb67-44" aria-hidden="true" tabindex="-1"></a>            if (associated)</span>
<span id="cb67-45"><a href="#cb67-45" aria-hidden="true" tabindex="-1"></a>                op.start();</span>
<span id="cb67-46"><a href="#cb67-46" aria-hidden="true" tabindex="-1"></a>            else</span>
<span id="cb67-47"><a href="#cb67-47" aria-hidden="true" tabindex="-1"></a>                set_stopped(std::move(*rcvr));</span>
<span id="cb67-48"><a href="#cb67-48" aria-hidden="true" tabindex="-1"></a>        }</span>
<span id="cb67-49"><a href="#cb67-49" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb67-50"><a href="#cb67-50" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb67-51"><a href="#cb67-51" aria-hidden="true" tabindex="-1"></a>    if (data.sndr.has_value())</span>
<span id="cb67-52"><a href="#cb67-52" aria-hidden="true" tabindex="-1"></a>        return op_state{std::forward_like&lt;Sndr&gt;(data.token), std::forward_like&lt;Sndr&gt;(*data.sndr), rcvr};</span>
<span id="cb67-53"><a href="#cb67-53" aria-hidden="true" tabindex="-1"></a>    else</span>
<span id="cb67-54"><a href="#cb67-54" aria-hidden="true" tabindex="-1"></a>        return op_state{data.token, rcvr};</span>
<span id="cb67-55"><a href="#cb67-55" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
The member <code class="sourceCode default"><em>impls-for</em>&lt;nest_t&gt;::<em>start</em></code>
is initialized with a callable object equivalent to the following
lambda:</p>
<div class="sourceCode" id="cb68"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb68-1"><a href="#cb68-1" aria-hidden="true" tabindex="-1"></a>[](auto&amp; state, auto&amp;) noexcept -&gt; void {</span>
<span id="cb68-2"><a href="#cb68-2" aria-hidden="true" tabindex="-1"></a>    state.start();</span>
<span id="cb68-3"><a href="#cb68-3" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">8</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>
</div>
<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>Add the following as a new subsection immediately after
<strong>[exec.nest]</strong>:</p>
<div class="add" style="color: #006e28">
<p><strong><code class="sourceCode default">std::execution::spawn_future</code>
[exec.spawn.future]</strong></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<code class="sourceCode default">spawn_future</code> attempts to
associate the given input sender with the given token’s async scope and,
on success, eagerly starts the input sender; the return value is a
sender that, when connected and started, completes with either the
result of the eagerly-started input sender or with
<code class="sourceCode default">set_stopped</code> if the input sender
was not started.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
The name <code class="sourceCode default">spawn_future</code> denotes a
customization point object. For subexpressions
<code class="sourceCode default">sndr</code>,
<code class="sourceCode default">token</code>, and
<code class="sourceCode default">env</code>, let
<code class="sourceCode default">Sndr</code> be
<code class="sourceCode default">decltype((sndr))</code>, let
<code class="sourceCode default">Token</code> be
<code class="sourceCode default">decltype((token))</code>, and let
<code class="sourceCode default">Env</code> be
<code class="sourceCode default">decltype((env))</code>. If
<code class="sourceCode default">sender&lt;Sndr&gt;</code> or
<code class="sourceCode default">async_scope_token&lt;Token&gt;</code>
is <code class="sourceCode default">false</code>, the expression
<code class="sourceCode default">spawn_future(sndr, token, env)</code>
is ill-formed.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
Let
<em><code class="sourceCode default">spawn-future-state-base</code></em>
be an exposition-only class template defined below:</p>
<div class="sourceCode" id="cb69"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb69-1"><a href="#cb69-1" aria-hidden="true" tabindex="-1"></a>namespace std::execution {</span>
<span id="cb69-2"><a href="#cb69-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb69-3"><a href="#cb69-3" aria-hidden="true" tabindex="-1"></a>template &lt;class Sigs&gt;</span>
<span id="cb69-4"><a href="#cb69-4" aria-hidden="true" tabindex="-1"></a>struct <em>spawn-future-state-base</em> { // <em>exposition-only</em></span>
<span id="cb69-5"><a href="#cb69-5" aria-hidden="true" tabindex="-1"></a>    variant&lt;/* <em>see below</em> */&gt; <em>result</em>; // <em>exposition-only</em></span>
<span id="cb69-6"><a href="#cb69-6" aria-hidden="true" tabindex="-1"></a>    virtual void <em>complete</em>() = 0; // <em>exposition-only</em></span>
<span id="cb69-7"><a href="#cb69-7" aria-hidden="true" tabindex="-1"></a>};</span>
<span id="cb69-8"><a href="#cb69-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb69-9"><a href="#cb69-9" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
The class template
<em><code class="sourceCode default">spawn-future-state-base</code></em>
can be instantiated with a type parameter,
<code class="sourceCode default">Sigs</code>, that is an instantiation
of <code class="sourceCode default">completion_signatures</code>. For an
instantiation of
<em><code class="sourceCode default">spawn-future-state-base</code></em>,
the result member has the type
<code class="sourceCode default">variant&lt;T...&gt;</code> where the
parameter pack contains the following:</p>
<ul>
<li><code class="sourceCode default">monostate</code> as the first
element;</li>
<li>for each completion signature in
<code class="sourceCode default">Sigs</code> with a completion tag
<code class="sourceCode default">cpo_t</code> and parameter types
<code class="sourceCode default">P...</code> an element of type <code class="sourceCode default"><em>decayed-tuple</em>&lt;cpo_t, P...&gt;</code>;
and</li>
<li><code class="sourceCode default"><em>decayed-tuple</em>&lt;set_error_t, exception_ptr&gt;</code>
if any of the preceding instantiations of
<code class="sourceCode default">tuple</code> have possibly-throwing
constructors.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
Let
<em><code class="sourceCode default">spawn-future-receiver</code></em>
be an exposition-only class template defined below:</p>
<div class="sourceCode" id="cb70"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb70-1"><a href="#cb70-1" aria-hidden="true" tabindex="-1"></a>namespace std::execution {</span>
<span id="cb70-2"><a href="#cb70-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb70-3"><a href="#cb70-3" aria-hidden="true" tabindex="-1"></a>template &lt;class Sigs&gt;</span>
<span id="cb70-4"><a href="#cb70-4" aria-hidden="true" tabindex="-1"></a>struct <em>spawn-future-receiver</em> { // <em>exposition-only</em></span>
<span id="cb70-5"><a href="#cb70-5" aria-hidden="true" tabindex="-1"></a>    using receiver_concept = receiver_t;</span>
<span id="cb70-6"><a href="#cb70-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb70-7"><a href="#cb70-7" aria-hidden="true" tabindex="-1"></a>    <em>spawn-future-state-base</em>&lt;Sigs&gt;* <em>state</em>; // <em>exposition-only</em></span>
<span id="cb70-8"><a href="#cb70-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb70-9"><a href="#cb70-9" aria-hidden="true" tabindex="-1"></a>    template &lt;class... T&gt;</span>
<span id="cb70-10"><a href="#cb70-10" aria-hidden="true" tabindex="-1"></a>    void set_value(T&amp;&amp;... t) &amp;&amp; noexcept {</span>
<span id="cb70-11"><a href="#cb70-11" aria-hidden="true" tabindex="-1"></a>        constexpr bool nothrow = (is_nothrow_constructible_v&lt;decay_t&lt;T&gt;, T&gt; &amp;&amp; ...);</span>
<span id="cb70-12"><a href="#cb70-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb70-13"><a href="#cb70-13" aria-hidden="true" tabindex="-1"></a>        try {</span>
<span id="cb70-14"><a href="#cb70-14" aria-hidden="true" tabindex="-1"></a>            <em>state</em>-&gt;<em>result</em>.template emplace&lt;<em>decayed-tuple</em>&lt;set_value_t, T...&gt;&gt;(set_value_t{}, std::forward&lt;T&gt;(t)...);</span>
<span id="cb70-15"><a href="#cb70-15" aria-hidden="true" tabindex="-1"></a>        }</span>
<span id="cb70-16"><a href="#cb70-16" aria-hidden="true" tabindex="-1"></a>        catch (...) {</span>
<span id="cb70-17"><a href="#cb70-17" aria-hidden="true" tabindex="-1"></a>            if constexpr (!nothrow) {</span>
<span id="cb70-18"><a href="#cb70-18" aria-hidden="true" tabindex="-1"></a>                <em>state</em>-&gt;<em>result</em>.template emplace&lt;<em>decayed-tuple</em>&lt;set_error_t, exception_ptr&gt;&gt;(set_error_t{}, current_exception());</span>
<span id="cb70-19"><a href="#cb70-19" aria-hidden="true" tabindex="-1"></a>            }</span>
<span id="cb70-20"><a href="#cb70-20" aria-hidden="true" tabindex="-1"></a>        }</span>
<span id="cb70-21"><a href="#cb70-21" aria-hidden="true" tabindex="-1"></a>        <em>state</em>-&gt;<em>complete</em>();</span>
<span id="cb70-22"><a href="#cb70-22" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb70-23"><a href="#cb70-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb70-24"><a href="#cb70-24" aria-hidden="true" tabindex="-1"></a>    template &lt;class E&gt;</span>
<span id="cb70-25"><a href="#cb70-25" aria-hidden="true" tabindex="-1"></a>    void set_error(E&amp;&amp; e) &amp;&amp; noexcept {</span>
<span id="cb70-26"><a href="#cb70-26" aria-hidden="true" tabindex="-1"></a>        constexpr bool nothrow = is_nothrow_constructible_v&lt;decay_t&lt;E&gt;, E&gt;;</span>
<span id="cb70-27"><a href="#cb70-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb70-28"><a href="#cb70-28" aria-hidden="true" tabindex="-1"></a>        try {</span>
<span id="cb70-29"><a href="#cb70-29" aria-hidden="true" tabindex="-1"></a>            <em>state</em>-&gt;<em>result</em>.template emplace&lt;<em>decayed-tuple</em>&lt;set_error_t, E&gt;&gt;(set_error_t{}, std::forward&lt;E&gt;(e));</span>
<span id="cb70-30"><a href="#cb70-30" aria-hidden="true" tabindex="-1"></a>        }</span>
<span id="cb70-31"><a href="#cb70-31" aria-hidden="true" tabindex="-1"></a>        catch (...) {</span>
<span id="cb70-32"><a href="#cb70-32" aria-hidden="true" tabindex="-1"></a>            if constexpr (!nothrow) {</span>
<span id="cb70-33"><a href="#cb70-33" aria-hidden="true" tabindex="-1"></a>                <em>state</em>-&gt;<em>result</em>.template emplace&lt;<em>decayed-tuple</em>&lt;set_error_t, exception_ptr&gt;&gt;(set_error_t{}, current_exception());</span>
<span id="cb70-34"><a href="#cb70-34" aria-hidden="true" tabindex="-1"></a>            }</span>
<span id="cb70-35"><a href="#cb70-35" aria-hidden="true" tabindex="-1"></a>        }</span>
<span id="cb70-36"><a href="#cb70-36" aria-hidden="true" tabindex="-1"></a>        <em>state</em>-&gt;<em>complete</em>();</span>
<span id="cb70-37"><a href="#cb70-37" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb70-38"><a href="#cb70-38" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb70-39"><a href="#cb70-39" aria-hidden="true" tabindex="-1"></a>    void set_stopped() &amp;&amp; noexcept {</span>
<span id="cb70-40"><a href="#cb70-40" aria-hidden="true" tabindex="-1"></a>        <em>state</em>-&gt;<em>result</em>.template emplace&lt;<em>decayed-tuple</em>&lt;set_stopped_t&gt;&gt;(set_stopped_t{});</span>
<span id="cb70-41"><a href="#cb70-41" aria-hidden="true" tabindex="-1"></a>        <em>state</em>-&gt;<em>complete</em>();</span>
<span id="cb70-42"><a href="#cb70-42" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb70-43"><a href="#cb70-43" aria-hidden="true" tabindex="-1"></a>};</span>
<span id="cb70-44"><a href="#cb70-44" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb70-45"><a href="#cb70-45" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
For the expression
<code class="sourceCode default">spawn_future(sndr, token, env)</code>
let <code class="sourceCode default">stok</code> be a stop token that
will receive stop requests sent from the returned future and any stop
requests sent to the stop token returned from
<code class="sourceCode default">get_stop_token(env)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
For the expression
<code class="sourceCode default">spawn_future(sndr, token, env)</code>
let <code class="sourceCode default">newSender</code> be the expression
<code class="sourceCode default">token.wrap(sndr)</code> and let
<code class="sourceCode default">alloc</code> and
<code class="sourceCode default">senv</code> be defined as follows:</p>
<ul>
<li>if the expression
<code class="sourceCode default">get_allocator(env)</code> is well
defined, then <code class="sourceCode default">alloc</code> is the
result of <code class="sourceCode default">get_allocator(env)</code> and
<code class="sourceCode default">senv</code> is the expression <code class="sourceCode default"><em>JOIN-ENV</em>(prop(get_stop_token, stok), env)</code>;</li>
<li>otherwise, if the expression <code class="sourceCode default">get_allocator(get_env(<em>new-sender</em>))</code>
is well-defined, then <code class="sourceCode default">alloc</code> is
the result of <code class="sourceCode default">get_allocator(get_env(<em>new-sender</em>))</code>
and <code class="sourceCode default">senv</code> is the expression <code class="sourceCode default"><em>JOIN-ENV</em>(<em>JOIN-ENV</em>(prop(get_allocator, alloc), prop(get_stop_token, stok)), env)</code>;</li>
<li>otherwise, <code class="sourceCode default">alloc</code> is
<code class="sourceCode default">std::allocator&lt;void&gt;</code> and
<code class="sourceCode default">senv</code> is the expression <code class="sourceCode default"><em>JOIN-ENV</em>(prop(get_stop_token, stok), env)</code>.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
Let <em><code class="sourceCode default">spawn-future-state</code></em>
be an exposition-only class template defined below:</p>
<div class="sourceCode" id="cb71"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb71-1"><a href="#cb71-1" aria-hidden="true" tabindex="-1"></a>namespace std::execution {</span>
<span id="cb71-2"><a href="#cb71-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb71-3"><a href="#cb71-3" aria-hidden="true" tabindex="-1"></a>template &lt;class Alloc, async_scope_token Token, sender Sender&gt;</span>
<span id="cb71-4"><a href="#cb71-4" aria-hidden="true" tabindex="-1"></a>struct <em>spawn-future-state</em> : <em>spawn-future-state-base</em>&lt;completion_signatures_of_t&lt;Sender, empty_env&gt;&gt; {</span>
<span id="cb71-5"><a href="#cb71-5" aria-hidden="true" tabindex="-1"></a>    using <em>sigs-t</em> = completion_signatures_of_t&lt;Sender, empty_env&gt;; // <em>exposition only</em></span>
<span id="cb71-6"><a href="#cb71-6" aria-hidden="true" tabindex="-1"></a>    using <em>receiver-t</em> = <em>spawn-future-receiver</em>&lt;<em>sigs-t</em>&gt;; // <em>exposition only</em></span>
<span id="cb71-7"><a href="#cb71-7" aria-hidden="true" tabindex="-1"></a>    using <em>op-t</em> = decltype(connect(declval&lt;Sender&gt;(), <em>receiver-t</em>{nullptr})); // <em>exposition only</em></span>
<span id="cb71-8"><a href="#cb71-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb71-9"><a href="#cb71-9" aria-hidden="true" tabindex="-1"></a>    <em>spawn-future-state</em>(Alloc alloc, Sender&amp;&amp; sndr, Token token) // <em>exposition only</em></span>
<span id="cb71-10"><a href="#cb71-10" aria-hidden="true" tabindex="-1"></a>        : <em>alloc</em>(std::move(alloc)),</span>
<span id="cb71-11"><a href="#cb71-11" aria-hidden="true" tabindex="-1"></a>          <em>op</em>(connect(std::move(sndr), <em>spawn-future-receiver</em>&lt;<em>sigt-t</em>&gt;{this})),</span>
<span id="cb71-12"><a href="#cb71-12" aria-hidden="true" tabindex="-1"></a>          <em>token</em>(std::move(token)) {}</span>
<span id="cb71-13"><a href="#cb71-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb71-14"><a href="#cb71-14" aria-hidden="true" tabindex="-1"></a>    void <em>run</em>(); // <em>exposition only</em></span>
<span id="cb71-15"><a href="#cb71-15" aria-hidden="true" tabindex="-1"></a>    void <em>complete</em>() override; // <em>exposition only</em></span>
<span id="cb71-16"><a href="#cb71-16" aria-hidden="true" tabindex="-1"></a>    void <em>consume</em>(receiver auto&amp; rcvr) noexcept; // <em>exposition only</em></span>
<span id="cb71-17"><a href="#cb71-17" aria-hidden="true" tabindex="-1"></a>    void <em>abandon</em>() noexcept; // <em>exposition only</em></span>
<span id="cb71-18"><a href="#cb71-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb71-19"><a href="#cb71-19" aria-hidden="true" tabindex="-1"></a>private:</span>
<span id="cb71-20"><a href="#cb71-20" aria-hidden="true" tabindex="-1"></a>    using <em>alloc-t</em> = typename allocator_traits&lt;Alloc&gt;::template rebind_alloc&lt;<em>spawn-future-state</em>&gt;;</span>
<span id="cb71-21"><a href="#cb71-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb71-22"><a href="#cb71-22" aria-hidden="true" tabindex="-1"></a>    <em>alloc-t</em> <em>alloc</em>; // <em>exposition only</em></span>
<span id="cb71-23"><a href="#cb71-23" aria-hidden="true" tabindex="-1"></a>    <em>op-t</em> <em>op</em>; // <em>exposition only</em></span>
<span id="cb71-24"><a href="#cb71-24" aria-hidden="true" tabindex="-1"></a>    Token <em>token</em>; // <em>exposition only</em></span>
<span id="cb71-25"><a href="#cb71-25" aria-hidden="true" tabindex="-1"></a>    bool <em>associated</em> = false; <em>exposition only</em></span>
<span id="cb71-26"><a href="#cb71-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb71-27"><a href="#cb71-27" aria-hidden="true" tabindex="-1"></a>    void <em>destroy</em>() noexcept; // <em>exposition only</em></span>
<span id="cb71-28"><a href="#cb71-28" aria-hidden="true" tabindex="-1"></a>};</span>
<span id="cb71-29"><a href="#cb71-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb71-30"><a href="#cb71-30" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><code class="sourceCode default">void <em>run</em>();</code></p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Effects</em>: Equivalent to:</p>
<div class="sourceCode" id="cb72"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb72-1"><a href="#cb72-1" aria-hidden="true" tabindex="-1"></a>    if (associated = token.try_associate())</span>
<span id="cb72-2"><a href="#cb72-2" aria-hidden="true" tabindex="-1"></a>        op.start();</span>
<span id="cb72-3"><a href="#cb72-3" aria-hidden="true" tabindex="-1"></a>    else {</span>
<span id="cb72-4"><a href="#cb72-4" aria-hidden="true" tabindex="-1"></a>        this-&gt;result.emplace&lt;<em>decayed-tuple</em>&lt;set_stopped_t&gt;&gt;(set_stopped_t{});</span>
<span id="cb72-5"><a href="#cb72-5" aria-hidden="true" tabindex="-1"></a>        <em>complete</em>();</span>
<span id="cb72-6"><a href="#cb72-6" aria-hidden="true" tabindex="-1"></a>    }</span></code></pre></div>
<p><code class="sourceCode default">void <em>complete</em>();</code></p>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span>
<em>Effects</em>:</p>
<ul>
<li>No effects if the invocation of
<em><code class="sourceCode default">complete</code></em> happens-before
an invocation of
<em><code class="sourceCode default">consume</code></em> or
<em><code class="sourceCode default">abandon</code></em>;</li>
<li>otherwise, if an invocation of
<em><code class="sourceCode default">consume</code></em> happened-before
this invocation of
<em><code class="sourceCode default">complete</code></em> then there is
a receiver, <code class="sourceCode default">rcvr</code>, registered and
that receiver is completed as if by
<code class="sourceCode default"><em>consume</em>(rcvr)</code>;</li>
<li>otherwise, an invocation of
<em><code class="sourceCode default">abandon</code></em> happened-before
this invocation of
<em><code class="sourceCode default">complete</code></em> and
<code class="sourceCode default"><em>destroy</em>()</code> is
invoked.</li>
</ul>
<p><code class="sourceCode default">void <em>consume</em>(receiver auto&amp; rcvr) noexcept;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Effects</em>:</p>
<ul>
<li><p>If the invocation of
<em><code class="sourceCode default">consume</code></em> happens-before
an invocation of
<em><code class="sourceCode default">complete</code></em> then
<code class="sourceCode default">rcvr</code> is registered to be
completed when <em><code class="sourceCode default">complete</code></em>
is invoked;</p></li>
<li><p>otherwise, <code class="sourceCode default">rcvr</code> is
completed as if by:</p>
<div class="sourceCode" id="cb73"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb73-1"><a href="#cb73-1" aria-hidden="true" tabindex="-1"></a>std::move(this-&gt;result).visit([&amp;rcvr](auto&amp;&amp; tuplish) noexcept {</span>
<span id="cb73-2"><a href="#cb73-2" aria-hidden="true" tabindex="-1"></a>   if constexpr (!same_as&lt;remove_reference_t&lt;decltype(tuplish)&gt;, monostate&gt;) {</span>
<span id="cb73-3"><a href="#cb73-3" aria-hidden="true" tabindex="-1"></a>       apply([&amp;rcvr](auto cpo, auto&amp;&amp;... vals) {</span>
<span id="cb73-4"><a href="#cb73-4" aria-hidden="true" tabindex="-1"></a>           cpo(std::move(rcvr), std::move(vals)...);</span>
<span id="cb73-5"><a href="#cb73-5" aria-hidden="true" tabindex="-1"></a>       }, std::move(tuplish));</span>
<span id="cb73-6"><a href="#cb73-6" aria-hidden="true" tabindex="-1"></a>   }</span>
<span id="cb73-7"><a href="#cb73-7" aria-hidden="true" tabindex="-1"></a>});</span></code></pre></div></li>
</ul>
<p><code class="sourceCode default">void <em>abandon</em>() noexcept;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">12</a></span>
<em>Effects</em>:</p>
<ul>
<li>If the invocation of
<em><code class="sourceCode default">abandon</code></em> happens-before
an invocation of
<em><code class="sourceCode default">complete</code></em> then a stop
request is sent to the spawned operation;</li>
<li>otherwise <code class="sourceCode default"><em>destroy</em>()</code>
is invoked.</li>
</ul>
<p><code class="sourceCode default">void <em>destroy</em>() noexcept;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">13</a></span>
<em>Effects</em>: Equivalent to:</p>
<div class="sourceCode" id="cb74"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb74-1"><a href="#cb74-1" aria-hidden="true" tabindex="-1"></a>    auto token = std::move(this-&gt;token);</span>
<span id="cb74-2"><a href="#cb74-2" aria-hidden="true" tabindex="-1"></a>    auto associated = this-&gt;associated;</span>
<span id="cb74-3"><a href="#cb74-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb74-4"><a href="#cb74-4" aria-hidden="true" tabindex="-1"></a>    {</span>
<span id="cb74-5"><a href="#cb74-5" aria-hidden="true" tabindex="-1"></a>        auto alloc = std::move(this-&gt;alloc);</span>
<span id="cb74-6"><a href="#cb74-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb74-7"><a href="#cb74-7" aria-hidden="true" tabindex="-1"></a>        allocator_traits&lt;<em>alloc-t</em>&gt;::destroy(alloc, this);</span>
<span id="cb74-8"><a href="#cb74-8" aria-hidden="true" tabindex="-1"></a>        allocator_traits&lt;<em>alloc-t</em>&gt;::deallocate(alloc, this, 1);</span>
<span id="cb74-9"><a href="#cb74-9" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb74-10"><a href="#cb74-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb74-11"><a href="#cb74-11" aria-hidden="true" tabindex="-1"></a>    if (associated)</span>
<span id="cb74-12"><a href="#cb74-12" aria-hidden="true" tabindex="-1"></a>        token.disassociate();</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">14</a></span> The
exposition-only class template
<em><code class="sourceCode default">impls-for</code></em>
([exec.snd.general]) is specialized for
<code class="sourceCode default">spawn_future_t</code> as follows:</p>
<div class="sourceCode" id="cb75"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb75-1"><a href="#cb75-1" aria-hidden="true" tabindex="-1"></a>namespace std::execution {</span>
<span id="cb75-2"><a href="#cb75-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb75-3"><a href="#cb75-3" aria-hidden="true" tabindex="-1"></a>template &lt;&gt;</span>
<span id="cb75-4"><a href="#cb75-4" aria-hidden="true" tabindex="-1"></a>struct <em>impls-for</em>&lt;spawn_future_t&gt; : <em>default-impls</em> {</span>
<span id="cb75-5"><a href="#cb75-5" aria-hidden="true" tabindex="-1"></a>    static constexpr auto <em>start</em> = <em>see below</em>;</span>
<span id="cb75-6"><a href="#cb75-6" aria-hidden="true" tabindex="-1"></a>};</span>
<span id="cb75-7"><a href="#cb75-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb75-8"><a href="#cb75-8" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">15</a></span> The
member <code class="sourceCode default"><em>impls-fors</em>&lt;spawn_future_t&gt;::<em>start</em></code>
is initialized with a callable object equivalent to the following
lambda:</p>
<div class="sourceCode" id="cb76"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb76-1"><a href="#cb76-1" aria-hidden="true" tabindex="-1"></a>[](auto&amp; state, auto&amp; rcvr) noexcept -&gt; void {</span>
<span id="cb76-2"><a href="#cb76-2" aria-hidden="true" tabindex="-1"></a>    state-&gt;<em>consume</em>(rcvr);</span>
<span id="cb76-3"><a href="#cb76-3" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">16</a></span> Then
the expression
<code class="sourceCode default">spawn_future(sndr, token)</code> is
expression-equivalent to <code class="sourceCode default">spawn_future(sndr, token, empty_env{})</code>
and the expression
<code class="sourceCode default">spawn_future(sndr, token, env)</code>
is expression-equivalent to the following:</p>
<div class="sourceCode" id="cb77"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb77-1"><a href="#cb77-1" aria-hidden="true" tabindex="-1"></a>    auto makeSender = [&amp;] {</span>
<span id="cb77-2"><a href="#cb77-2" aria-hidden="true" tabindex="-1"></a>        return write_env(token.wrap(std::forward&lt;Sender&gt;(sndr)), senv);</span>
<span id="cb77-3"><a href="#cb77-3" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb77-4"><a href="#cb77-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb77-5"><a href="#cb77-5" aria-hidden="true" tabindex="-1"></a>    using <em>sender-t</em> = decltype(makeSender());</span>
<span id="cb77-6"><a href="#cb77-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb77-7"><a href="#cb77-7" aria-hidden="true" tabindex="-1"></a>    using <em>state-t</em> = <em>spawn-future-state</em>&lt;decltype(alloc), Token, <em>sender-t</em>&gt;;</span>
<span id="cb77-8"><a href="#cb77-8" aria-hidden="true" tabindex="-1"></a>    using <em>alloc-t</em> = typename allocator_traits&lt;decltype(alloc)&gt;::template rebind_alloc&lt;<em>state-t</em>&gt;;</span>
<span id="cb77-9"><a href="#cb77-9" aria-hidden="true" tabindex="-1"></a>    using <em>traits-t</em> = allocator_traits&lt;<em>alloc-t</em>&gt;;</span>
<span id="cb77-10"><a href="#cb77-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb77-11"><a href="#cb77-11" aria-hidden="true" tabindex="-1"></a>    <em>alloc-t</em> stateAlloc{alloc};</span>
<span id="cb77-12"><a href="#cb77-12" aria-hidden="true" tabindex="-1"></a>    auto* op = <em>traits-t</em>::allocate(stateAlloc, 1);</span>
<span id="cb77-13"><a href="#cb77-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb77-14"><a href="#cb77-14" aria-hidden="true" tabindex="-1"></a>    try {</span>
<span id="cb77-15"><a href="#cb77-15" aria-hidden="true" tabindex="-1"></a>        <em>traits-t</em>::construct(stateAlloc, op, alloc, makeSender(), token);</span>
<span id="cb77-16"><a href="#cb77-16" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb77-17"><a href="#cb77-17" aria-hidden="true" tabindex="-1"></a>    catch(...) {</span>
<span id="cb77-18"><a href="#cb77-18" aria-hidden="true" tabindex="-1"></a>        <em>traits-t</em>::deallocate(stateAlloc, op, 1);</span>
<span id="cb77-19"><a href="#cb77-19" aria-hidden="true" tabindex="-1"></a>        throw;</span>
<span id="cb77-20"><a href="#cb77-20" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb77-21"><a href="#cb77-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb77-22"><a href="#cb77-22" aria-hidden="true" tabindex="-1"></a>    try {</span>
<span id="cb77-23"><a href="#cb77-23" aria-hidden="true" tabindex="-1"></a>        op-&gt;<em>run</em>();</span>
<span id="cb77-24"><a href="#cb77-24" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb77-25"><a href="#cb77-25" aria-hidden="true" tabindex="-1"></a>    catch(...) {</span>
<span id="cb77-26"><a href="#cb77-26" aria-hidden="true" tabindex="-1"></a>        <em>traits-t</em>::destroy(stateAlloc, op);</span>
<span id="cb77-27"><a href="#cb77-27" aria-hidden="true" tabindex="-1"></a>        <em>traits-t</em>::deallocate(stateAlloc, op, 1);</span>
<span id="cb77-28"><a href="#cb77-28" aria-hidden="true" tabindex="-1"></a>        throw;</span>
<span id="cb77-29"><a href="#cb77-29" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb77-30"><a href="#cb77-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb77-31"><a href="#cb77-31" aria-hidden="true" tabindex="-1"></a>    struct deleter {</span>
<span id="cb77-32"><a href="#cb77-32" aria-hidden="true" tabindex="-1"></a>        void operator()(<em>state-t</em> p) noexcept {</span>
<span id="cb77-33"><a href="#cb77-33" aria-hidden="true" tabindex="-1"></a>             if (p)</span>
<span id="cb77-34"><a href="#cb77-34" aria-hidden="true" tabindex="-1"></a>                 p-&gt;<em>abandon</em>();</span>
<span id="cb77-35"><a href="#cb77-35" aria-hidden="true" tabindex="-1"></a>        }</span>
<span id="cb77-36"><a href="#cb77-36" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb77-37"><a href="#cb77-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb77-38"><a href="#cb77-38" aria-hidden="true" tabindex="-1"></a>    return <em>make-sender</em>(spawn_future, unique_ptr&lt;<em>state-t</em>, deleter&gt;{op});</span></code></pre></div>

</div>
<h2 data-number="8.5" id="executionspawn-1"><span class="header-section-number">8.5</span>
<code class="sourceCode default">execution::spawn</code><a href="#executionspawn-1" class="self-link"></a></h2>
<p>Add the following as a new subsection at the end of <span>33.9.13
<a href="https://wg21.link/exec.consumers">[exec.consumers]</a></span>:</p>
<div class="add" style="color: #006e28">
<p><strong><code class="sourceCode default">std::execution::spawn</code>
[exec.spawn]</strong></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<code class="sourceCode default">spawn</code> attempts to associate the
given input sender with the given token’s async scope and, on success,
eagerly starts the input sender.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
The name <code class="sourceCode default">spawn</code> denotes a
customization point object. For subexpressions
<code class="sourceCode default">sndr</code>,
<code class="sourceCode default">token</code>, and
<code class="sourceCode default">env</code>, let
<code class="sourceCode default">Sndr</code> be
<code class="sourceCode default">decltype((sndr))</code>, let
<code class="sourceCode default">Token</code> be
<code class="sourceCode default">decltype((token))</code>, and let
<code class="sourceCode default">Env</code> be
<code class="sourceCode default">decltype((env))</code>. If
<code class="sourceCode default">sender&lt;Sndr&gt;</code> or
<code class="sourceCode default">async_scope_token&lt;Token&gt;</code>
is <code class="sourceCode default">false</code>, the expression
<code class="sourceCode default">spawn(sndr, token, env)</code> is
ill-formed.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
Let <em><code class="sourceCode default">spawn-state-base</code></em> be
an exposition only class defined below:</p>
<div class="sourceCode" id="cb78"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb78-1"><a href="#cb78-1" aria-hidden="true" tabindex="-1"></a>namespace std::execution {</span>
<span id="cb78-2"><a href="#cb78-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb78-3"><a href="#cb78-3" aria-hidden="true" tabindex="-1"></a>struct <em>spawn-state-base</em> { // exposition-only</span>
<span id="cb78-4"><a href="#cb78-4" aria-hidden="true" tabindex="-1"></a>    virtual void <em>complete</em>() = 0; // exposition-only</span>
<span id="cb78-5"><a href="#cb78-5" aria-hidden="true" tabindex="-1"></a>};</span>
<span id="cb78-6"><a href="#cb78-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb78-7"><a href="#cb78-7" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
Let <em><code class="sourceCode default">spawn-receiver</code></em> be
an exposition only class defined below:</p>
<div class="sourceCode" id="cb79"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb79-1"><a href="#cb79-1" aria-hidden="true" tabindex="-1"></a>namespace std::execution {</span>
<span id="cb79-2"><a href="#cb79-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb79-3"><a href="#cb79-3" aria-hidden="true" tabindex="-1"></a>struct <em>spawn-receiver</em> { // exposition-only</span>
<span id="cb79-4"><a href="#cb79-4" aria-hidden="true" tabindex="-1"></a>    using receiver_concept = receiver_t;</span>
<span id="cb79-5"><a href="#cb79-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb79-6"><a href="#cb79-6" aria-hidden="true" tabindex="-1"></a>    <em>spawn-state-base</em>* state; // exposition-only</span>
<span id="cb79-7"><a href="#cb79-7" aria-hidden="true" tabindex="-1"></a>    void set_value() &amp;&amp; noexcept { state-&gt;<em>complete</em>(); }</span>
<span id="cb79-8"><a href="#cb79-8" aria-hidden="true" tabindex="-1"></a>    void set_stopped() &amp;&amp; noexcept { state-&gt;<em>complete</em>(); }</span>
<span id="cb79-9"><a href="#cb79-9" aria-hidden="true" tabindex="-1"></a>};</span>
<span id="cb79-10"><a href="#cb79-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb79-11"><a href="#cb79-11" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
For the expression
<code class="sourceCode default">spawn(sndr, token, env)</code> let
<em><code class="sourceCode default">new-sender</code></em> be the
expression <code class="sourceCode default">token.wrap(sndr)</code> and
let <code class="sourceCode default">alloc</code> and
<code class="sourceCode default">senv</code> be defined as follows:</p>
<ul>
<li>if the expression
<code class="sourceCode default">get_allocator(env)</code> is well
defined, then <code class="sourceCode default">alloc</code> is the
result of <code class="sourceCode default">get_allocator(env)</code> and
<code class="sourceCode default">senv</code> is the expression
<code class="sourceCode default">env</code>,</li>
<li>otherwise if the expression <code class="sourceCode default">get_allocator(get_env(<em>new-sender</em>))</code>
is well-defined, then <code class="sourceCode default">alloc</code> is
the result of <code class="sourceCode default">get_allocator(get_env(<em>new-sender</em>))</code>
and <code class="sourceCode default">senv</code> is the expression <code class="sourceCode default"><em>JOIN-ENV</em>(env, prop(get_allocator, alloc))</code></li>
<li>otherwise <code class="sourceCode default">alloc</code> is
<code class="sourceCode default">std::allocator&lt;void&gt;{}</code> and
<code class="sourceCode default">senv</code> is the expression
<code class="sourceCode default">env</code></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
Let <em><code class="sourceCode default">spawn-state</code></em> be an
exposition only class template defined below:</p>
<div class="sourceCode" id="cb80"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb80-1"><a href="#cb80-1" aria-hidden="true" tabindex="-1"></a>namespace std::execution {</span>
<span id="cb80-2"><a href="#cb80-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb80-3"><a href="#cb80-3" aria-hidden="true" tabindex="-1"></a>template &lt;class Alloc, async_scope_token Token, sender Sender&gt;</span>
<span id="cb80-4"><a href="#cb80-4" aria-hidden="true" tabindex="-1"></a>struct <em>spawn-state</em> : <em>spawn-state-base</em> {</span>
<span id="cb80-5"><a href="#cb80-5" aria-hidden="true" tabindex="-1"></a>    using <em>op-t</em> = decltype(connect(declval&lt;Sender&gt;(), <em>spawn-receiver</em>{nullptr}));</span>
<span id="cb80-6"><a href="#cb80-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb80-7"><a href="#cb80-7" aria-hidden="true" tabindex="-1"></a>    <em>spawn-state</em>(Alloc alloc, Sender&amp;&amp; sndr, Token token); // see below</span>
<span id="cb80-8"><a href="#cb80-8" aria-hidden="true" tabindex="-1"></a>    void <em>run</em>(); // see below</span>
<span id="cb80-9"><a href="#cb80-9" aria-hidden="true" tabindex="-1"></a>    void <em>complete</em>() override; // see below</span>
<span id="cb80-10"><a href="#cb80-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb80-11"><a href="#cb80-11" aria-hidden="true" tabindex="-1"></a>private:</span>
<span id="cb80-12"><a href="#cb80-12" aria-hidden="true" tabindex="-1"></a>    using <em>alloc-t</em> = typename allocator_traits&lt;Alloc&gt;::template rebind_alloc&lt;<em>spawn-state</em>&gt;;</span>
<span id="cb80-13"><a href="#cb80-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb80-14"><a href="#cb80-14" aria-hidden="true" tabindex="-1"></a>    <em>alloc-t</em> alloc;</span>
<span id="cb80-15"><a href="#cb80-15" aria-hidden="true" tabindex="-1"></a>    <em>op-t</em> op;</span>
<span id="cb80-16"><a href="#cb80-16" aria-hidden="true" tabindex="-1"></a>    Token token;</span>
<span id="cb80-17"><a href="#cb80-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb80-18"><a href="#cb80-18" aria-hidden="true" tabindex="-1"></a>    void <em>destroy</em>() noexcept; // see below</span>
<span id="cb80-19"><a href="#cb80-19" aria-hidden="true" tabindex="-1"></a>};</span>
<span id="cb80-20"><a href="#cb80-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb80-21"><a href="#cb80-21" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><code class="sourceCode default"><em>spawn-state</em>(Alloc alloc, Sender&amp;&amp; sndr, Token token);</code></p>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Effects</em>: Equivalent to:</p>
<div class="sourceCode" id="cb81"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb81-1"><a href="#cb81-1" aria-hidden="true" tabindex="-1"></a>    this-&gt;alloc = alloc;</span>
<span id="cb81-2"><a href="#cb81-2" aria-hidden="true" tabindex="-1"></a>    this-&gt;op = connect(std::move(sndr), <em>spawn-receiver</em>{this});</span>
<span id="cb81-3"><a href="#cb81-3" aria-hidden="true" tabindex="-1"></a>    this-&gt;token = token;</span></code></pre></div>
<p><code class="sourceCode default">void <em>run</em>();</code></p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Effects</em>: Equivalent to:</p>
<div class="sourceCode" id="cb82"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb82-1"><a href="#cb82-1" aria-hidden="true" tabindex="-1"></a>    if (token.try_associate())</span>
<span id="cb82-2"><a href="#cb82-2" aria-hidden="true" tabindex="-1"></a>        op.start();</span>
<span id="cb82-3"><a href="#cb82-3" aria-hidden="true" tabindex="-1"></a>    else</span>
<span id="cb82-4"><a href="#cb82-4" aria-hidden="true" tabindex="-1"></a>        <em>destroy</em>();</span></code></pre></div>
<p><code class="sourceCode default">void <em>complete</em>() override;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span>
<em>Effects</em>: Equivalent to:</p>
<div class="sourceCode" id="cb83"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb83-1"><a href="#cb83-1" aria-hidden="true" tabindex="-1"></a>    auto token = std::move(this-&gt;token);</span>
<span id="cb83-2"><a href="#cb83-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb83-3"><a href="#cb83-3" aria-hidden="true" tabindex="-1"></a>    <em>destroy</em>();</span>
<span id="cb83-4"><a href="#cb83-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb83-5"><a href="#cb83-5" aria-hidden="true" tabindex="-1"></a>    token.disassociate();</span></code></pre></div>
<p><code class="sourceCode default">void <em>destroy</em>() noexcept;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Effects</em>: Equivalent to:</p>
<div class="sourceCode" id="cb84"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb84-1"><a href="#cb84-1" aria-hidden="true" tabindex="-1"></a>    auto alloc = std::move(this-&gt;alloc);</span>
<span id="cb84-2"><a href="#cb84-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb84-3"><a href="#cb84-3" aria-hidden="true" tabindex="-1"></a>    allocator_traits&lt;<em>alloc-t</em>&gt;::destroy(alloc, this);</span>
<span id="cb84-4"><a href="#cb84-4" aria-hidden="true" tabindex="-1"></a>    allocator_traits&lt;<em>alloc-t</em>&gt;::deallocate(alloc, this, 1);</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">12</a></span> Then
the expression
<code class="sourceCode default">spawn(sndr, token)</code> is
expression-equivalent to
<code class="sourceCode default">spawn(sndr, token, empty_env{})</code>
and the expression
<code class="sourceCode default">spawn(sndr, token, env)</code> is
expression-equivalent to the following:</p>
<div class="sourceCode" id="cb85"><pre class="sourceCode default default"><code class="sourceCode default"><span id="cb85-1"><a href="#cb85-1" aria-hidden="true" tabindex="-1"></a>    auto makeSender = [&amp;] {</span>
<span id="cb85-2"><a href="#cb85-2" aria-hidden="true" tabindex="-1"></a>        return write_env(token.wrap(std::forward&lt;Sender&gt;(sndr)), senv);</span>
<span id="cb85-3"><a href="#cb85-3" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb85-4"><a href="#cb85-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb85-5"><a href="#cb85-5" aria-hidden="true" tabindex="-1"></a>    using <em>sender-t</em> = decltype(makeSender());</span>
<span id="cb85-6"><a href="#cb85-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb85-7"><a href="#cb85-7" aria-hidden="true" tabindex="-1"></a>    using <em>state-t</em> = <em>spawn-state</em>&lt;decltype(alloc), Token, <em>sender-t</em>&gt;;</span>
<span id="cb85-8"><a href="#cb85-8" aria-hidden="true" tabindex="-1"></a>    using <em>alloc-t</em> = typename allocator_traits&lt;decltype(alloc)&gt;::template rebind_alloc&lt;<em>state-t</em>&gt;;</span>
<span id="cb85-9"><a href="#cb85-9" aria-hidden="true" tabindex="-1"></a>    using <em>traits-t</em> = allocator_traits&lt;<em>alloc-t</em>&gt;;</span>
<span id="cb85-10"><a href="#cb85-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb85-11"><a href="#cb85-11" aria-hidden="true" tabindex="-1"></a>    <em>alloc-t</em> stateAlloc{alloc};</span>
<span id="cb85-12"><a href="#cb85-12" aria-hidden="true" tabindex="-1"></a>    auto* op = <em>traits-t</em>::allocate(stateAlloc, 1);</span>
<span id="cb85-13"><a href="#cb85-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb85-14"><a href="#cb85-14" aria-hidden="true" tabindex="-1"></a>    try {</span>
<span id="cb85-15"><a href="#cb85-15" aria-hidden="true" tabindex="-1"></a>        <em>traits-t</em>::construct(stateAlloc, op, alloc, makeSender(), token);</span>
<span id="cb85-16"><a href="#cb85-16" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb85-17"><a href="#cb85-17" aria-hidden="true" tabindex="-1"></a>    catch(...) {</span>
<span id="cb85-18"><a href="#cb85-18" aria-hidden="true" tabindex="-1"></a>        <em>traits-t</em>::deallocate(stateAlloc, op, 1);</span>
<span id="cb85-19"><a href="#cb85-19" aria-hidden="true" tabindex="-1"></a>        throw;</span>
<span id="cb85-20"><a href="#cb85-20" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb85-21"><a href="#cb85-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb85-22"><a href="#cb85-22" aria-hidden="true" tabindex="-1"></a>    try {</span>
<span id="cb85-23"><a href="#cb85-23" aria-hidden="true" tabindex="-1"></a>        op-&gt;<em>run</em>();</span>
<span id="cb85-24"><a href="#cb85-24" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb85-25"><a href="#cb85-25" aria-hidden="true" tabindex="-1"></a>    catch(...) {</span>
<span id="cb85-26"><a href="#cb85-26" aria-hidden="true" tabindex="-1"></a>        <em>traits-t</em>::destroy(stateAlloc, op);</span>
<span id="cb85-27"><a href="#cb85-27" aria-hidden="true" tabindex="-1"></a>        <em>traits-t</em>::deallocate(stateAlloc, op, 1);</span>
<span id="cb85-28"><a href="#cb85-28" aria-hidden="true" tabindex="-1"></a>        throw;</span>
<span id="cb85-29"><a href="#cb85-29" aria-hidden="true" tabindex="-1"></a>    }</span></code></pre></div>

</div>
<h2 data-number="8.6" id="async-scope-utilities"><span class="header-section-number">8.6</span> Async scope utilities<a href="#async-scope-utilities" class="self-link"></a></h2>
<p>Add the following as a new subsection immediately after <span>33.13
<a href="https://wg21.link/exec.coro.util">[exec.coro.util]</a></span>:</p>
<div class="add" style="color: #006e28">
<p><strong>Async scope utilities [exec.scope]</strong></p>
</div>
<h2 data-number="8.7" id="async-scope-concepts"><span class="header-section-number">8.7</span> Async scope concepts<a href="#async-scope-concepts" class="self-link"></a></h2>
<p>Add the following as the first subsection of
<strong>[exec.scope]</strong>:</p>
<div class="add" style="color: #006e28">
<p><strong>Scope concepts [exec.scope.concepts]</strong></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The
<code class="sourceCode default">async_scope_token&lt;Token&gt;</code>
concept defines the requirements on a type
<code class="sourceCode default">Token</code> that can be used to create
associations between senders and an async scope.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
Let <em><code class="sourceCode default">test-sender</code></em> and
<em><code class="sourceCode default">test-env</code></em> be unspecified
types such that <code class="sourceCode default">sender_in&lt;<em>test-sender</em>, <em>test-env</em>&gt;</code>
is <code class="sourceCode default">true</code>.</p>
<div class="sourceCode" id="cb86"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb86-1"><a href="#cb86-1" aria-hidden="true" tabindex="-1"></a>namespace std::execution {</span>
<span id="cb86-2"><a href="#cb86-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb86-3"><a href="#cb86-3" aria-hidden="true" tabindex="-1"></a>template &lt;class Token&gt;</span>
<span id="cb86-4"><a href="#cb86-4" aria-hidden="true" tabindex="-1"></a>concept async_scope_token =</span>
<span id="cb86-5"><a href="#cb86-5" aria-hidden="true" tabindex="-1"></a>    copyable&lt;Token&gt; &amp;&amp;</span>
<span id="cb86-6"><a href="#cb86-6" aria-hidden="true" tabindex="-1"></a>    requires(Token token) {</span>
<span id="cb86-7"><a href="#cb86-7" aria-hidden="true" tabindex="-1"></a>        { token.try_associate() } -&gt; same_as&lt;bool&gt;;</span>
<span id="cb86-8"><a href="#cb86-8" aria-hidden="true" tabindex="-1"></a>        { token.disassociate() } -&gt; same_as&lt;void&gt;;</span>
<span id="cb86-9"><a href="#cb86-9" aria-hidden="true" tabindex="-1"></a>        { token.wrap(declval&lt;<em>test-sender</em>&gt;()) } -&gt; sender_in&lt;<em>test-env</em>&gt;;</span>
<span id="cb86-10"><a href="#cb86-10" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb86-11"><a href="#cb86-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb86-12"><a href="#cb86-12" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<code class="sourceCode default">async_scope_token&lt;Token&gt;</code>
is modeled only if <code class="sourceCode default">Token</code>’s copy
operations, move operations, and
<code class="sourceCode default">disassociate</code> method do not exit
with an exception.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
Let <code class="sourceCode default">token</code> be an expression, and
let <code class="sourceCode default">Token</code> be
<code class="sourceCode default">decltype((token))</code>.
<code class="sourceCode default">Token</code> models
<code class="sourceCode default">async_scope_token</code> only if, for
all expressions <code class="sourceCode default">sndr</code> whose type
models <code class="sourceCode default">sender</code>,
<code class="sourceCode default">token.wrap(sndr)</code> is a valid
expression whose type models
<code class="sourceCode default">sender</code> and whose advertised
completion signatures are the same as those advertised by
<code class="sourceCode default">sndr</code>.</p>
</div>
<h2 data-number="8.8" id="executionsimple_counting_scope-and-executioncounting_scope"><span class="header-section-number">8.8</span>
<code class="sourceCode default">execution::simple_counting_scope</code>
and <code class="sourceCode default">execution::counting_scope</code><a href="#executionsimple_counting_scope-and-executioncounting_scope" class="self-link"></a></h2>
<p>Add the following new section immediately after
<strong>[exec.scope.concepts]</strong>:</p>
<div class="add" style="color: #006e28">
<p><strong>Simple Counting Scope
[exec.scope.simple.counting]</strong></p>
<p><strong>General [exec.scope.simple.counting.general]</strong></p>
<div class="sourceCode" id="cb87"><pre class="sourceCode default default"><code class="sourceCode default"><span id="cb87-1"><a href="#cb87-1" aria-hidden="true" tabindex="-1"></a>class simple_counting_scope {</span>
<span id="cb87-2"><a href="#cb87-2" aria-hidden="true" tabindex="-1"></a>public:</span>
<span id="cb87-3"><a href="#cb87-3" aria-hidden="true" tabindex="-1"></a>    // [exec.simple.counting.token], token</span>
<span id="cb87-4"><a href="#cb87-4" aria-hidden="true" tabindex="-1"></a>    struct token {</span>
<span id="cb87-5"><a href="#cb87-5" aria-hidden="true" tabindex="-1"></a>        template &lt;sender Sender&gt;</span>
<span id="cb87-6"><a href="#cb87-6" aria-hidden="true" tabindex="-1"></a>        Sender&amp;&amp; wrap(Sender&amp;&amp; snd) const noexcept;</span>
<span id="cb87-7"><a href="#cb87-7" aria-hidden="true" tabindex="-1"></a>        bool try_associate() const;</span>
<span id="cb87-8"><a href="#cb87-8" aria-hidden="true" tabindex="-1"></a>        void disassociate() const;</span>
<span id="cb87-9"><a href="#cb87-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb87-10"><a href="#cb87-10" aria-hidden="true" tabindex="-1"></a>    private:</span>
<span id="cb87-11"><a href="#cb87-11" aria-hidden="true" tabindex="-1"></a>        simple_counting_scope* <em>scope</em>; // <em>exposition-only</em></span>
<span id="cb87-12"><a href="#cb87-12" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb87-13"><a href="#cb87-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb87-14"><a href="#cb87-14" aria-hidden="true" tabindex="-1"></a>    struct <em>join-t</em>; // <em>exposition-only</em></span>
<span id="cb87-15"><a href="#cb87-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb87-16"><a href="#cb87-16" aria-hidden="true" tabindex="-1"></a>    enum <em>state-type</em> { // <em>exposition-only</em></span>
<span id="cb87-17"><a href="#cb87-17" aria-hidden="true" tabindex="-1"></a>        <em>unused</em>, // <em>exposition-only</em></span>
<span id="cb87-18"><a href="#cb87-18" aria-hidden="true" tabindex="-1"></a>        <em>open</em>, // <em>exposition-only</em></span>
<span id="cb87-19"><a href="#cb87-19" aria-hidden="true" tabindex="-1"></a>        <em>close</em>, // <em>exposition-only</em></span>
<span id="cb87-20"><a href="#cb87-20" aria-hidden="true" tabindex="-1"></a>        <em>open-and-joining</em>, // <em>exposition-only</em></span>
<span id="cb87-21"><a href="#cb87-21" aria-hidden="true" tabindex="-1"></a>        <em>closed-and-joining</em>, // <em>exposition-only</em></span>
<span id="cb87-22"><a href="#cb87-22" aria-hidden="true" tabindex="-1"></a>        <em>unused-and-closed</em>, // <em>exposition-only</em></span>
<span id="cb87-23"><a href="#cb87-23" aria-hidden="true" tabindex="-1"></a>        <em>joined</em>, // <em>exposition-only</em></span>
<span id="cb87-24"><a href="#cb87-24" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb87-25"><a href="#cb87-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb87-26"><a href="#cb87-26" aria-hidden="true" tabindex="-1"></a>    // [exec.simple.counting.ctor], constructor and destructor</span>
<span id="cb87-27"><a href="#cb87-27" aria-hidden="true" tabindex="-1"></a>    simple_counting_scope() noexcept;</span>
<span id="cb87-28"><a href="#cb87-28" aria-hidden="true" tabindex="-1"></a>    simple_counting_scope(simple_counting_scope&amp;&amp;) = delete;</span>
<span id="cb87-29"><a href="#cb87-29" aria-hidden="true" tabindex="-1"></a>    ~simple_counting_scope();</span>
<span id="cb87-30"><a href="#cb87-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb87-31"><a href="#cb87-31" aria-hidden="true" tabindex="-1"></a>    // [exec.simple.counting.mem], members</span>
<span id="cb87-32"><a href="#cb87-32" aria-hidden="true" tabindex="-1"></a>    token get_token() noexcept;</span>
<span id="cb87-33"><a href="#cb87-33" aria-hidden="true" tabindex="-1"></a>    void close() noexcept;</span>
<span id="cb87-34"><a href="#cb87-34" aria-hidden="true" tabindex="-1"></a>    auto join() noexcept;</span>
<span id="cb87-35"><a href="#cb87-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb87-36"><a href="#cb87-36" aria-hidden="true" tabindex="-1"></a>private:</span>
<span id="cb87-37"><a href="#cb87-37" aria-hidden="true" tabindex="-1"></a>    size_t <em>count</em>; // <em>exposition-only</em></span>
<span id="cb87-38"><a href="#cb87-38" aria-hidden="true" tabindex="-1"></a>    <em>state-type</em> <em>state</em>; // <em>exposition-only</em></span>
<span id="cb87-39"><a href="#cb87-39" aria-hidden="true" tabindex="-1"></a>};</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
A <code class="sourceCode default">simple_counting_scope</code>
maintains a count of outstanding operations. Let
<code class="sourceCode default">s</code> be an object of type
<code class="sourceCode default">simple_counting_scope</code>,
<code class="sourceCode default">t</code> be an object of type
<code class="sourceCode default">simple_counting_scope::token</code>
obtained from <code class="sourceCode default">s.get_token()</code>, let
<code class="sourceCode default">j</code> be a sender obtained from
<code class="sourceCode default">s.join()</code>, and let
<code class="sourceCode default">o</code> be an operation state obtained
from connecting <code class="sourceCode default">j</code> to a receiver.
During its life-time <code class="sourceCode default">s</code> goes
through different states which govern what operations are allowed and
the result of these operations:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code class="sourceCode default"><em>unused</em></code>: a newly
constructed object starts in the
<code class="sourceCode default"><em>unused</em></code> state.</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code class="sourceCode default"><em>open</em></code>: when
<code class="sourceCode default">t.try_associate()</code> is called
while <code class="sourceCode default">s</code> is in
<code class="sourceCode default"><em>unused</em></code> state,
<code class="sourceCode default">s</code> moves to the
<code class="sourceCode default"><em>open</em></code> state.</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span>
<code class="sourceCode default"><em>open-and-joining</em></code>: when
the operation state <code class="sourceCode default">o</code> is started
while the <code class="sourceCode default">s</code> is in
<code class="sourceCode default"><em>unused</em></code> or
<code class="sourceCode default"><em>open</em></code> state,
<code class="sourceCode default">s</code> moves to the
<code class="sourceCode default"><em>open-and-joining</em></code>
state.</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span>
<code class="sourceCode default"><em>closed</em></code>: when
<code class="sourceCode default">s.close()</code> is called while
<code class="sourceCode default">s</code> is in
<code class="sourceCode default">open</code> state,
<code class="sourceCode default">s</code> moves to the
<code class="sourceCode default"><em>closed</em></code> state.</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.5)</a></span>
<code class="sourceCode default"><em>unused-and-closed</em></code>: when
<code class="sourceCode default">s.close()</code> is called while
<code class="sourceCode default">s</code> is in
<code class="sourceCode default"><em>unused</em></code> state,
<code class="sourceCode default">s</code> moves to the
<code class="sourceCode default"><em>unused-and-closed</em></code>
state.</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.6)</a></span>
<code class="sourceCode default"><em>closed-and-joining</em></code>:
when <code class="sourceCode default">s.close()</code> is called while
<code class="sourceCode default">s</code> is in
<code class="sourceCode default"><em>open-and-joining</em></code> state
or the operation state <code class="sourceCode default">o</code> is
started while <code class="sourceCode default">s</code> is in
<code class="sourceCode default"><em>closed</em></code> or
<code class="sourceCode default"><em>unused-and-closed</em></code>
state, <code class="sourceCode default">s</code> moves to the
<code class="sourceCode default"><em>closed-and-joining</em></code>
state.</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.7)</a></span>
<code class="sourceCode default"><em>joined</em></code>: when the count
of associated objects drops to zero while
<code class="sourceCode default">s</code> is in
<code class="sourceCode default"><em>open-and-joining</em></code> or
<code class="sourceCode default"><em>closed-and-joining</em></code>
state, <code class="sourceCode default">s</code> moves to the
<code class="sourceCode default"><em>joined</em></code> state.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
Calls to member functions
<code class="sourceCode default">get_token</code>,
<code class="sourceCode default">close</code>, and
<code class="sourceCode default">join</code> do not introduce data
races.</p>
<p><strong>Constructor and Destructor
[exec.simple.counting.ctor]</strong></p>
<p><code class="sourceCode default">simple_counting_scope() noexcept;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Postcondtions:</em>
<code class="sourceCode default"><em>count</em></code> is
<code class="sourceCode default">0</code> and
<code class="sourceCode default"><em>state</em></code> is
<code class="sourceCode default"><em>unused</em></code></p>
<p><code class="sourceCode default">~simple_counting_scope();</code></p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em> If
<code class="sourceCode default"><em>state</em></code> is not one of
<code class="sourceCode default"><em>joined</em></code>,
<code class="sourceCode default"><em>unused</em></code>, or
<code class="sourceCode default"><em>unused-and-closed</em></code>,
invokes <code class="sourceCode default">terminate</code> (<span>14.6.2
<a href="https://wg21.link/except.terminate">[except.terminate]</a></span>).
Otherwise, has no effects.</p>
<p><strong>Members [exec.simple.counting.mem]</strong></p>
<p><code class="sourceCode default">token get_token() noexcept;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Returns:</em> An object <code class="sourceCode default">t</code> of
type
<code class="sourceCode default">simple_counting_scope::token</code>
such that
<code class="sourceCode default">t.<em>scope</em> == this</code> is
<code class="sourceCode default">true</code>.</p>
<p><code class="sourceCode default">void close() noexcept;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em> If
<code class="sourceCode default"><em>state</em></code> is</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code class="sourceCode default"><em>unused</em></code> changes
<code class="sourceCode default"><em>state</em></code> to
<code class="sourceCode default"><em>unused-and-closed</em></code>;</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code class="sourceCode default"><em>open</em></code> changes
<code class="sourceCode default"><em>state</em></code> to
<code class="sourceCode default"><em>closed</em></code>;</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
<code class="sourceCode default"><em>open-and-joining</em></code>
changes <code class="sourceCode default"><em>state</em></code> to
<code class="sourceCode default"><em>closed-and-joining</em></code>;</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
Any call to <code class="sourceCode default">t.try_associate()</code>
for a <code class="sourceCode default">token</code> object
<code class="sourceCode default">t</code> referring to a
<code class="sourceCode default">simple_counting_scope</code> object
<code class="sourceCode default">s</code> which happens after a call to
<code class="sourceCode default">s.close()</code> returns
<code class="sourceCode default">false</code>.</p>
<p><code class="sourceCode default">sender auto join() noexcept;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Returns:</em> <code class="sourceCode default"><em>make_sender</em>(<em>join-t</em>, this)</code></p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
The exposition-only class template
<code class="sourceCode default"><em>impls-for</em></code> (<span>33.9.1
<a href="https://wg21.link/exec.snd.general">[exec.snd.general]</a></span>)
is specialized for
<code class="sourceCode default"><em>join-t</em></code> as follows:</p>
<div class="sourceCode" id="cb88"><pre class="sourceCode default default"><code class="sourceCode default"><span id="cb88-1"><a href="#cb88-1" aria-hidden="true" tabindex="-1"></a>template &lt;&gt;</span>
<span id="cb88-2"><a href="#cb88-2" aria-hidden="true" tabindex="-1"></a>struct <em>impls-for</em>&lt;<em>join-t</em>&gt;: <em>default-impls</em> {</span>
<span id="cb88-3"><a href="#cb88-3" aria-hidden="true" tabindex="-1"></a>    template &lt;class Receiver&gt;</span>
<span id="cb88-4"><a href="#cb88-4" aria-hidden="true" tabindex="-1"></a>    struct <em>state</em> {  // <em>exposition-only</em></span>
<span id="cb88-5"><a href="#cb88-5" aria-hidden="true" tabindex="-1"></a>        simple_counting_scope* <em>scope</em>; // <em>exposition-only</em></span>
<span id="cb88-6"><a href="#cb88-6" aria-hidden="true" tabindex="-1"></a>        remove_cvref_t&lt;Receiver&gt;&amp; <em>receiver</em>; // <em>exposition-only</em></span>
<span id="cb88-7"><a href="#cb88-7" aria-hidden="true" tabindex="-1"></a>        using <em>op_t</em> = decltype(connect(schedule(get_scheduler(get_env(receiver))), receiver)); // <em>exposition-only</em></span>
<span id="cb88-8"><a href="#cb88-8" aria-hidden="true" tabindex="-1"></a>        <em>op_t</em> <em>op</em>; // <em>exposition-only</em></span>
<span id="cb88-9"><a href="#cb88-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb88-10"><a href="#cb88-10" aria-hidden="true" tabindex="-1"></a>        <em>state</em>(simple_counting_scope* scope, Receiver&amp; receiver) // <em>exposition-only</em></span>
<span id="cb88-11"><a href="#cb88-11" aria-hidden="true" tabindex="-1"></a>          : <em>scope</em>(scope),</span>
<span id="cb88-12"><a href="#cb88-12" aria-hidden="true" tabindex="-1"></a>            <em>receiver</em>(receiver),</span>
<span id="cb88-13"><a href="#cb88-13" aria-hidden="true" tabindex="-1"></a>            <em>op</em>(connect(schedule(get_scheduler(get_env(receiver))), receiver)) {}</span>
<span id="cb88-14"><a href="#cb88-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb88-15"><a href="#cb88-15" aria-hidden="true" tabindex="-1"></a>        void <em>complete</em>() { // <em>exposition-only</em></span>
<span id="cb88-16"><a href="#cb88-16" aria-hidden="true" tabindex="-1"></a>            <em>op</em>.start();</span>
<span id="cb88-17"><a href="#cb88-17" aria-hidden="true" tabindex="-1"></a>        }</span>
<span id="cb88-18"><a href="#cb88-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb88-19"><a href="#cb88-19" aria-hidden="true" tabindex="-1"></a>        void <em>complete-inline</em>() { // <em>exposition-only</em></span>
<span id="cb88-20"><a href="#cb88-20" aria-hidden="true" tabindex="-1"></a>            set_value(std::move(<em>receiver</em>));</span>
<span id="cb88-21"><a href="#cb88-21" aria-hidden="true" tabindex="-1"></a>        }</span>
<span id="cb88-22"><a href="#cb88-22" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb88-23"><a href="#cb88-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb88-24"><a href="#cb88-24" aria-hidden="true" tabindex="-1"></a>    static constexpr auto <em>get-state</em> =</span>
<span id="cb88-25"><a href="#cb88-25" aria-hidden="true" tabindex="-1"></a>        []&lt;class Receiver&gt;(auto&amp;&amp; sender, Receiver&amp; receiver) {</span>
<span id="cb88-26"><a href="#cb88-26" aria-hidden="true" tabindex="-1"></a>            auto[_, self] = sender;</span>
<span id="cb88-27"><a href="#cb88-27" aria-hidden="true" tabindex="-1"></a>            return <em>state</em>&lt;Receiver&gt;(self, receiver);</span>
<span id="cb88-28"><a href="#cb88-28" aria-hidden="true" tabindex="-1"></a>        };</span>
<span id="cb88-29"><a href="#cb88-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb88-30"><a href="#cb88-30" aria-hidden="true" tabindex="-1"></a>    static constexpr auto <em>start</em> =</span>
<span id="cb88-31"><a href="#cb88-31" aria-hidden="true" tabindex="-1"></a>        [](auto&amp; s, auto&amp;) { <em>see-below</em>; };</span>
<span id="cb88-32"><a href="#cb88-32" aria-hidden="true" tabindex="-1"></a>};</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
In the function object used to initialize <code class="sourceCode default"><em>impls-for</em>&lt;<em>join-t</em>&gt;::<em>start</em></code>
let state be
<code class="sourceCode default">s.<em>scope</em>-&gt;<em>state</em></code>.
If state is</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(7.1)</a></span>
<code class="sourceCode default"><em>unused</em></code>,
<code class="sourceCode default"><em>unused-and-closed</em></code>, or
<code class="sourceCode default"><em>joined</em></code>,
<code class="sourceCode default">s.<em>complete-inline</em>()</code> is
invoked and changes the state of
<code class="sourceCode default">*s.<em>scope</em></code> to
<code class="sourceCode default"><em>joined</em></code>;</li>
<li><span class="marginalizedparent"><a class="marginalized">(7.2)</a></span>
<code class="sourceCode default"><em>open</em></code>, changes the state
of <code class="sourceCode default">*s.<em>scope</em></code> to
<code class="sourceCode default"><em>open-and-joining</em></code>;</li>
<li><span class="marginalizedparent"><a class="marginalized">(7.3)</a></span>
<code class="sourceCode default"><em>closed</em></code>, changes the
state of <code class="sourceCode default">*s.<em>scope</em></code> to
<code class="sourceCode default"><em>closed-and-joining</em></code>;</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
If <code class="sourceCode default">s.<em>complete-inline</em>()</code>
was not invoked, registers s with
<code class="sourceCode default">*s.<em>scope</em></code> to have
<code class="sourceCode default">s.<em>complete</em>()</code> invoked
when
<code class="sourceCode default">s.<em>scope</em>-&gt;<em>count</em></code>
becomes zero.</p>
<p><strong>Token [exec.simple.counting.token]</strong></p>
<p><code class="sourceCode default">template &lt;sender Sender&gt;</code><br />
<code class="sourceCode default">Sender&amp;&amp; wrap(Sender&amp;&amp; snd) const noexcept;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Returns:</em>
<code class="sourceCode default">std::forward&lt;Sender&gt;(snd);</code></p>
<p><code class="sourceCode default">bool try_associate() const;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em> A invocation of this member function has the following
atomic effect:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> If
<code class="sourceCode default"><em>scope</em>-&gt;<em>state</em></code>
is not one of <code class="sourceCode default"><em>unused</em></code>,
<code class="sourceCode default"><em>open</em></code>, or
<code class="sourceCode default"><em>open-and-joining</em></code> the
operation has no effect;</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
otherwise increment
<code class="sourceCode default"><em>scope</em>-&gt;<em>count</em></code>
and if <code class="sourceCode default"><em>scope</em>-&gt;<em>state</em> == <em>unused</em></code>
change this value to
<code class="sourceCode default"><em>open</em></code>.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Returns:</em> <code class="sourceCode default">true</code> if
<code class="sourceCode default"><em>scope</em>-&gt;<em>count</em></code>
was incremented, <code class="sourceCode default">false</code>
otherwise.</p>
<p><code class="sourceCode default">void disassociate() const;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects</em>: Decrements
<code class="sourceCode default"><em>scope</em>-&gt;<em>count</em></code>.
If
<code class="sourceCode default"><em>scope</em>-&gt;<em>count</em></code>
is zero after decrementing and
<code class="sourceCode default"><em>scope</em>-&gt;<em>state</em></code>
is <code class="sourceCode default"><em>open-and-joining</em></code> or
<code class="sourceCode default"><em>closed-and-joining</em></code>,
changes the state of
<code class="sourceCode default">*<em>scope</em></code> to
<code class="sourceCode default"><em>joined</em></code> and calls
<code class="sourceCode default"><em>complete</em>()</code> on all
objects registered with
<code class="sourceCode default">*<em>scope</em></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
[<em>Note:</em> Calling
<code class="sourceCode default"><em>complete</em>()</code> on any
registered object may cause
<code class="sourceCode default">*<em>scope</em></code> to get
destroyed. <em>–End-Note</em>]</p>
<p><strong>Counting Scope [exec.counting.scope]</strong></p>
<p><strong>General [exec.counting.general]</strong></p>
<div class="sourceCode" id="cb89"><pre class="sourceCode default default"><code class="sourceCode default"><span id="cb89-1"><a href="#cb89-1" aria-hidden="true" tabindex="-1"></a>class counting_scope {</span>
<span id="cb89-2"><a href="#cb89-2" aria-hidden="true" tabindex="-1"></a>public:</span>
<span id="cb89-3"><a href="#cb89-3" aria-hidden="true" tabindex="-1"></a>    // [exec.counting.token], token</span>
<span id="cb89-4"><a href="#cb89-4" aria-hidden="true" tabindex="-1"></a>    struct token {</span>
<span id="cb89-5"><a href="#cb89-5" aria-hidden="true" tabindex="-1"></a>        template &lt;sender Sender&gt;</span>
<span id="cb89-6"><a href="#cb89-6" aria-hidden="true" tabindex="-1"></a>        sender auto wrap(Sender&amp;&amp; snd) const noexcept;</span>
<span id="cb89-7"><a href="#cb89-7" aria-hidden="true" tabindex="-1"></a>        bool try_associate() const;</span>
<span id="cb89-8"><a href="#cb89-8" aria-hidden="true" tabindex="-1"></a>        void disassociate() const;</span>
<span id="cb89-9"><a href="#cb89-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb89-10"><a href="#cb89-10" aria-hidden="true" tabindex="-1"></a>    private:</span>
<span id="cb89-11"><a href="#cb89-11" aria-hidden="true" tabindex="-1"></a>        counting_scope* <em>scope</em>; // <em>exposition-only</em></span>
<span id="cb89-12"><a href="#cb89-12" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb89-13"><a href="#cb89-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb89-14"><a href="#cb89-14" aria-hidden="true" tabindex="-1"></a>    struct <em>join-t</em>; // <em>exposition-only</em></span>
<span id="cb89-15"><a href="#cb89-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb89-16"><a href="#cb89-16" aria-hidden="true" tabindex="-1"></a>    enum <em>state-type</em> { // <em>exposition-only</em></span>
<span id="cb89-17"><a href="#cb89-17" aria-hidden="true" tabindex="-1"></a>        <em>unused</em>, // <em>exposition-only</em></span>
<span id="cb89-18"><a href="#cb89-18" aria-hidden="true" tabindex="-1"></a>        <em>open</em>, // <em>exposition-only</em></span>
<span id="cb89-19"><a href="#cb89-19" aria-hidden="true" tabindex="-1"></a>        <em>close</em>, // <em>exposition-only</em></span>
<span id="cb89-20"><a href="#cb89-20" aria-hidden="true" tabindex="-1"></a>        <em>open-and-joining</em>, // <em>exposition-only</em></span>
<span id="cb89-21"><a href="#cb89-21" aria-hidden="true" tabindex="-1"></a>        <em>closed-and-joining</em>, // <em>exposition-only</em></span>
<span id="cb89-22"><a href="#cb89-22" aria-hidden="true" tabindex="-1"></a>        <em>unused-and-closed</em>, // <em>exposition-only</em></span>
<span id="cb89-23"><a href="#cb89-23" aria-hidden="true" tabindex="-1"></a>        <em>joined</em>, // <em>exposition-only</em></span>
<span id="cb89-24"><a href="#cb89-24" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb89-25"><a href="#cb89-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb89-26"><a href="#cb89-26" aria-hidden="true" tabindex="-1"></a>    // [exec.counting.ctor], constructor and destructor</span>
<span id="cb89-27"><a href="#cb89-27" aria-hidden="true" tabindex="-1"></a>    counting_scope() noexcept;</span>
<span id="cb89-28"><a href="#cb89-28" aria-hidden="true" tabindex="-1"></a>    counting_scope(counting_scope&amp;&amp;) = delete;</span>
<span id="cb89-29"><a href="#cb89-29" aria-hidden="true" tabindex="-1"></a>    ~counting_scope();</span>
<span id="cb89-30"><a href="#cb89-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb89-31"><a href="#cb89-31" aria-hidden="true" tabindex="-1"></a>    // [exec.counting.mem], members</span>
<span id="cb89-32"><a href="#cb89-32" aria-hidden="true" tabindex="-1"></a>    token get_token() noexcept;</span>
<span id="cb89-33"><a href="#cb89-33" aria-hidden="true" tabindex="-1"></a>    void close() noexcept;</span>
<span id="cb89-34"><a href="#cb89-34" aria-hidden="true" tabindex="-1"></a>    auto join() noexcept;</span>
<span id="cb89-35"><a href="#cb89-35" aria-hidden="true" tabindex="-1"></a>    void request_stop() noexcept;</span>
<span id="cb89-36"><a href="#cb89-36" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb89-37"><a href="#cb89-37" aria-hidden="true" tabindex="-1"></a>private:</span>
<span id="cb89-38"><a href="#cb89-38" aria-hidden="true" tabindex="-1"></a>    size_t <em>count</em>; // <em>exposition-only</em></span>
<span id="cb89-39"><a href="#cb89-39" aria-hidden="true" tabindex="-1"></a>    <em>state-type</em> <em>state</em>; // <em>exposition-only</em></span>
<span id="cb89-40"><a href="#cb89-40" aria-hidden="true" tabindex="-1"></a>    inplace_stop_source <em>s_source</em> // <em>exposition-only</em></span>
<span id="cb89-41"><a href="#cb89-41" aria-hidden="true" tabindex="-1"></a>};</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
A <code class="sourceCode default">counting_scope</code> maintains a
count of outstanding operations. Let
<code class="sourceCode default">s</code> be an object of type
<code class="sourceCode default">counting_scope</code>,
<code class="sourceCode default">t</code> be an object of type
<code class="sourceCode default">counting_scope::token</code> obtained
from <code class="sourceCode default">s.get_token()</code>, let
<code class="sourceCode default">j</code> be a sender obtained from
<code class="sourceCode default">s.join()</code>, and let
<code class="sourceCode default">o</code> be an operation state obtained
from connecting <code class="sourceCode default">j</code> to a receiver.
During its life-time <code class="sourceCode default">s</code> goes
through different states which govern what operations are allowed and
the result of these operations:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code class="sourceCode default"><em>unused</em></code>: a newly
constructed object starts in the
<code class="sourceCode default"><em>unused</em></code> state.</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code class="sourceCode default"><em>open</em></code>: when
<code class="sourceCode default">t.try_associate()</code> is called
while <code class="sourceCode default">s</code> is in
<code class="sourceCode default"><em>unused</em></code> state,
<code class="sourceCode default">s</code> moves to the
<code class="sourceCode default"><em>open</em></code> state.</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span>
<code class="sourceCode default"><em>open-and-joining</em></code>: when
the operation state <code class="sourceCode default">o</code> is started
while the <code class="sourceCode default">s</code> is in
<code class="sourceCode default"><em>unused</em></code> or
<code class="sourceCode default"><em>open</em></code> state,
<code class="sourceCode default">s</code> moves to the
<code class="sourceCode default"><em>open-and-joining</em></code>
state.</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span>
<code class="sourceCode default"><em>closed</em></code>: when
<code class="sourceCode default">s.close()</code> is called while
<code class="sourceCode default">s</code> is in
<code class="sourceCode default">open</code> state,
<code class="sourceCode default">s</code> moves to the
<code class="sourceCode default"><em>closed</em></code> state.</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.5)</a></span>
<code class="sourceCode default"><em>unused-and-closed</em></code>: when
<code class="sourceCode default">s.close()</code> is called while
<code class="sourceCode default">s</code> is in
<code class="sourceCode default"><em>unused</em></code> state,
<code class="sourceCode default">s</code> moves to the
<code class="sourceCode default"><em>unused-and-closed</em></code>
state.</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.6)</a></span>
<code class="sourceCode default"><em>closed-and-joining</em></code>:
when <code class="sourceCode default">s.close()</code> is called while
<code class="sourceCode default">s</code> is in
<code class="sourceCode default"><em>open-and-joining</em></code> state
or the operation state <code class="sourceCode default">o</code> is
started while <code class="sourceCode default">s</code> is in
<code class="sourceCode default"><em>closed</em></code> or
<code class="sourceCode default"><em>unused-and-closed</em></code>
state, <code class="sourceCode default">s</code> moves to the
<code class="sourceCode default"><em>closed-and-joining</em></code>
state.</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.7)</a></span>
<code class="sourceCode default"><em>joined</em></code>: when the count
of associated objects drops to zero while
<code class="sourceCode default">s</code> is in
<code class="sourceCode default"><em>open-and-joining</em></code> or
<code class="sourceCode default"><em>closed-and-joining</em></code>
state, <code class="sourceCode default">s</code> moves to the
<code class="sourceCode default"><em>joined</em></code> state.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
Calls to member functions
<code class="sourceCode default">get_token</code>,
<code class="sourceCode default">close</code>,
<code class="sourceCode default">join</code>, and
<code class="sourceCode default">request_stop</code> do not introduce
data races.</p>
<p><strong>Constructor and Destructor [exec.counting.ctor]</strong></p>
<p><code class="sourceCode default">counting_scope() noexcept;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Postcondtions:</em>
<code class="sourceCode default"><em>count</em></code> is
<code class="sourceCode default">0</code> and
<code class="sourceCode default"><em>state</em></code> is
<code class="sourceCode default"><em>unused</em></code></p>
<p><code class="sourceCode default">~counting_scope();</code></p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em> If
<code class="sourceCode default"><em>state</em></code> is not one of
<code class="sourceCode default"><em>joined</em></code>,
<code class="sourceCode default"><em>unused</em></code>, or
<code class="sourceCode default"><em>unused-and-closed</em></code>,
invokes <code class="sourceCode default">terminate</code> (<span>14.6.2
<a href="https://wg21.link/except.terminate">[except.terminate]</a></span>).
Otherwise, has no effects.</p>
<p><strong>Members [exec.counting.mem]</strong></p>
<p><code class="sourceCode default">token get_token() noexcept;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Returns:</em> An object <code class="sourceCode default">t</code> of
type <code class="sourceCode default">counting_scope::token</code> such
that <code class="sourceCode default">t.<em>scope</em> == this</code> is
<code class="sourceCode default">true</code>.</p>
<p><code class="sourceCode default">void close() noexcept;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em> If
<code class="sourceCode default"><em>state</em></code> is</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code class="sourceCode default"><em>unused</em></code> changes
<code class="sourceCode default"><em>state</em></code> to
<code class="sourceCode default"><em>unused-and-closed</em></code>;</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code class="sourceCode default"><em>open</em></code> changes
<code class="sourceCode default"><em>state</em></code> to
<code class="sourceCode default"><em>closed</em></code>;</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
<code class="sourceCode default"><em>open-and-joining</em></code>
changes <code class="sourceCode default"><em>state</em></code> to
<code class="sourceCode default"><em>closed-and-joining</em></code>;</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
Any call to <code class="sourceCode default">t.try_associate()</code>
for a <code class="sourceCode default">token</code> object
<code class="sourceCode default">t</code> referring to a
<code class="sourceCode default">counting_scope</code> object
<code class="sourceCode default">s</code> which happens after a call to
<code class="sourceCode default">s.close()</code> returns
<code class="sourceCode default">false</code>.</p>
<p><code class="sourceCode default">sender auto join() noexcept;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Returns:</em> <code class="sourceCode default"><em>make_sender</em>(<em>join-t</em>, this)</code></p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
The exposition-only class template
<code class="sourceCode default"><em>impls-for</em></code> (<span>33.9.1
<a href="https://wg21.link/exec.snd.general">[exec.snd.general]</a></span>)
is specialized for
<code class="sourceCode default"><em>join-t</em></code> as follows:</p>
<div class="sourceCode" id="cb90"><pre class="sourceCode default default"><code class="sourceCode default"><span id="cb90-1"><a href="#cb90-1" aria-hidden="true" tabindex="-1"></a>template &lt;&gt;</span>
<span id="cb90-2"><a href="#cb90-2" aria-hidden="true" tabindex="-1"></a>struct <em>impls-for</em>&lt;<em>join-t</em>&gt;: <em>default-impls</em> {</span>
<span id="cb90-3"><a href="#cb90-3" aria-hidden="true" tabindex="-1"></a>    template &lt;class Receiver&gt;</span>
<span id="cb90-4"><a href="#cb90-4" aria-hidden="true" tabindex="-1"></a>    struct <em>state</em> {  // <em>exposition-only</em></span>
<span id="cb90-5"><a href="#cb90-5" aria-hidden="true" tabindex="-1"></a>        counting_scope* <em>scope</em>; // <em>exposition-only</em></span>
<span id="cb90-6"><a href="#cb90-6" aria-hidden="true" tabindex="-1"></a>        remove_cvref_t&lt;Receiver&gt;&amp; <em>receiver</em>; // <em>exposition-only</em></span>
<span id="cb90-7"><a href="#cb90-7" aria-hidden="true" tabindex="-1"></a>        using <em>op_t</em> = decltype(connect(schedule(get_scheduler(get_env(receiver))), receiver)); // <em>exposition-only</em></span>
<span id="cb90-8"><a href="#cb90-8" aria-hidden="true" tabindex="-1"></a>        <em>op_t</em> <em>op</em>; // <em>exposition-only</em></span>
<span id="cb90-9"><a href="#cb90-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb90-10"><a href="#cb90-10" aria-hidden="true" tabindex="-1"></a>        <em>state</em>(counting_scope* scope, Receiver&amp; receiver) // <em>exposition-only</em></span>
<span id="cb90-11"><a href="#cb90-11" aria-hidden="true" tabindex="-1"></a>          : <em>scope</em>(scope),</span>
<span id="cb90-12"><a href="#cb90-12" aria-hidden="true" tabindex="-1"></a>            <em>receiver</em>(receiver),</span>
<span id="cb90-13"><a href="#cb90-13" aria-hidden="true" tabindex="-1"></a>            <em>op</em>(connect(schedule(get_scheduler(get_env(receiver))), receiver)) {}</span>
<span id="cb90-14"><a href="#cb90-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb90-15"><a href="#cb90-15" aria-hidden="true" tabindex="-1"></a>        void <em>complete</em>() { // <em>exposition-only</em></span>
<span id="cb90-16"><a href="#cb90-16" aria-hidden="true" tabindex="-1"></a>            <em>op</em>.start();</span>
<span id="cb90-17"><a href="#cb90-17" aria-hidden="true" tabindex="-1"></a>        }</span>
<span id="cb90-18"><a href="#cb90-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb90-19"><a href="#cb90-19" aria-hidden="true" tabindex="-1"></a>        void <em>complete-inline</em>() { // <em>exposition-only</em></span>
<span id="cb90-20"><a href="#cb90-20" aria-hidden="true" tabindex="-1"></a>            set_value(std::move(<em>receiver</em>));</span>
<span id="cb90-21"><a href="#cb90-21" aria-hidden="true" tabindex="-1"></a>        }</span>
<span id="cb90-22"><a href="#cb90-22" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb90-23"><a href="#cb90-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb90-24"><a href="#cb90-24" aria-hidden="true" tabindex="-1"></a>    static constexpr auto <em>get-state</em> =</span>
<span id="cb90-25"><a href="#cb90-25" aria-hidden="true" tabindex="-1"></a>        []&lt;class Receiver&gt;(auto&amp;&amp; sender, Receiver&amp; receiver) {</span>
<span id="cb90-26"><a href="#cb90-26" aria-hidden="true" tabindex="-1"></a>            auto[_, self] = sender;</span>
<span id="cb90-27"><a href="#cb90-27" aria-hidden="true" tabindex="-1"></a>            return <em>state</em>&lt;Receiver&gt;(self, receiver);</span>
<span id="cb90-28"><a href="#cb90-28" aria-hidden="true" tabindex="-1"></a>        };</span>
<span id="cb90-29"><a href="#cb90-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb90-30"><a href="#cb90-30" aria-hidden="true" tabindex="-1"></a>    static constexpr auto <em>start</em> =</span>
<span id="cb90-31"><a href="#cb90-31" aria-hidden="true" tabindex="-1"></a>        [](auto&amp; s, auto&amp;) { <em>see-below</em>; };</span>
<span id="cb90-32"><a href="#cb90-32" aria-hidden="true" tabindex="-1"></a>};</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
In the function object used to initialize <code class="sourceCode default"><em>impls-for</em>&lt;<em>join-t</em>&gt;::<em>start</em></code>
let state be
<code class="sourceCode default">s.<em>scope</em>-&gt;<em>state</em></code>.
If state is</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(7.1)</a></span>
<code class="sourceCode default"><em>unused</em></code>,
<code class="sourceCode default"><em>unused-and-closed</em></code>, or
<code class="sourceCode default"><em>joined</em></code>,
<code class="sourceCode default">s.<em>complete-inline</em>()</code> is
invoked and changes the state of
<code class="sourceCode default">*s.<em>scope</em></code> to
<code class="sourceCode default"><em>joined</em></code>;</li>
<li><span class="marginalizedparent"><a class="marginalized">(7.2)</a></span>
<code class="sourceCode default"><em>open</em></code>, changes the state
of <code class="sourceCode default">*s.<em>scope</em></code> to
<code class="sourceCode default"><em>open-and-joining</em></code>;</li>
<li><span class="marginalizedparent"><a class="marginalized">(7.3)</a></span>
<code class="sourceCode default"><em>closed</em></code>, changes the
state of <code class="sourceCode default">*s.<em>scope</em></code> to
<code class="sourceCode default"><em>closed-and-joining</em></code>;</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
If <code class="sourceCode default">s.<em>complete-inline</em>()</code>
was not invoked, registers s with
<code class="sourceCode default">*s.<em>scope</em></code> to have
<code class="sourceCode default">s.<em>complete</em>()</code> invoked
when
<code class="sourceCode default">s.<em>scope</em>-&gt;<em>count</em></code>
becomes zero.</p>
<p><code class="sourceCode default">void request_stop() noexcept</code></p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Effects</em>: Calls
<code class="sourceCode default"><em>s_source</em>.request_stop()</code></p>
<p><strong>Token [exec.counting.token]</strong></p>
<p><code class="sourceCode default">template &lt;sender Sender&gt;</code><br />
<code class="sourceCode default">sender auto wrap(Sender&amp;&amp; snd) const noexcept;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Returns:</em> Sender <code class="sourceCode default">osnd</code>
from an exposition-only sender algorithm <em><code class="sourceCode default">stop_when(sender auto&amp;&amp; snd, stoppable_token auto stoken)</code></em>
that maps its input sender,
<em><code class="sourceCode default">snd</code></em>, 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,
<em><code class="sourceCode default">snd</code></em>, to
<code class="sourceCode default">r</code>, except that the operation
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
<em><code class="sourceCode default">stoken</code></em> receives a stop
request.</p>
<p><code class="sourceCode default">bool try_associate() const;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em> A invocation of this member function has the following
atomic effect:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> If
<code class="sourceCode default"><em>scope</em>-&gt;<em>state</em></code>
is not one of <code class="sourceCode default"><em>unused</em></code>,
<code class="sourceCode default"><em>open</em></code>, or
<code class="sourceCode default"><em>open-and-joining</em></code> the
operation has no effect;</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
otherwise increment
<code class="sourceCode default"><em>scope</em>-&gt;<em>count</em></code>
and if <code class="sourceCode default"><em>scope</em>-&gt;<em>state</em> == <em>unused</em></code>
change this value to
<code class="sourceCode default"><em>open</em></code>.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Returns:</em> <code class="sourceCode default">true</code> if
<code class="sourceCode default"><em>scope</em>-&gt;<em>count</em></code>
was incremented, <code class="sourceCode default">false</code>
otherwise.</p>
<p><code class="sourceCode default">void disassociate() const;</code></p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects</em>: If
<code class="sourceCode default"><em>scope</em>-&gt;<em>count</em></code>
is zero after decrementing and
<code class="sourceCode default"><em>scope</em>-&gt;<em>state</em></code>
is <code class="sourceCode default"><em>open-and-joining</em></code> or
<code class="sourceCode default"><em>closed-and-joining</em></code>,
changes the state of
<code class="sourceCode default">*<em>scope</em></code> to
<code class="sourceCode default"><em>joined</em></code> and calls
<code class="sourceCode default"><em>complete</em>()</code> on all
objects registered with
<code class="sourceCode default">*<em>scope</em></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
[<em>Note:</em> Calling
<code class="sourceCode default"><em>complete</em>()</code> on any
registered object may cause
<code class="sourceCode default">*<em>scope</em></code> to get
destroyed. <em>–End-Note</em>]</p>
</div>
<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 Daisy Hollman, Nico Josuttis, Zach Laine, Jonathan Müller,
and David Sankel for fruitful discussions about regularity.</p>
<p>Thanks to Lewis Baker, Robert Leahy, Dmitry Prokoptsev, Anthony
Williams, and everyone else who contributed to discussions leading to
this paper.</p>
<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-P3296R2" class="csl-entry" role="doc-biblioentry">
[P3296R2] Anthony Williams. let_async_scope. <a href="https://wg21.link/p3296r2"><div class="csl-block">https://wg21.link/p3296r2</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>
