<!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="2022-07-14" />
  <title>System execution context</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.hanging-indent{margin-left: 1.5em; text-indent: -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; }
      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">System execution context</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2079R3</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2022-07-14</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, LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Lee Howes<br>&lt;<a href="mailto:lwh@fb.com" class="email">lwh@fb.com</a>&gt;<br>
      Ruslan Arutyunyan<br>&lt;<a href="mailto:ruslan.arutyunyan@intel.com" class="email">ruslan.arutyunyan@intel.com</a>&gt;<br>
      Michael Voss<br>&lt;<a href="mailto:michaelj.voss@intel.com" class="email">michaelj.voss@intel.com</a>&gt;<br>
    </td>
  </tr>
</table>

</header>
<div style="clear:both">
<h1 data-number="1" id="abtract"><span class="header-section-number">1</span> Abtract<a href="#abtract" class="self-link"></a></h1>
<p>A standard execution context based on the facilities in <span class="citation" data-cites="P2300">[<a href="#ref-P2300" role="doc-biblioref">P2300</a>]</span> that implements parallel-forward-progress to maximise portability. A set of <code class="sourceCode default">system_context</code>s share an underlying shared thread pool implementation, and may provide an interface to an OS-provided system thread pool.</p>
<h1 data-number="2" id="changes"><span class="header-section-number">2</span> Changes<a href="#changes" class="self-link"></a></h1>
<h2 data-number="2.1" id="r3"><span class="header-section-number">2.1</span> R3<a href="#r3" class="self-link"></a></h2>
<ul>
<li>Remove <code class="sourceCode default">execute_all</code> and <code class="sourceCode default">execute_chunk</code>. Replace with compile-time customization and a design discussion.</li>
<li>Add design discussion about the approach we should take for customization and the extent to which the context should be implementation-defined.</li>
<li>Add design discussion for an explicit <code class="sourceCode default">system_context</code> class.</li>
<li>Add design discussion about priorities.</li>
</ul>
<h2 data-number="2.2" id="r2"><span class="header-section-number">2.2</span> R2<a href="#r2" class="self-link"></a></h2>
<ul>
<li>Significant redesign to fit in P2300 model.</li>
<li>Strictly limit to parallel progress without control over the level of parallelism.</li>
<li>Remove direct support for task groups, delegating that to <code class="sourceCode default">async_scope</code>.</li>
</ul>
<h2 data-number="2.3" id="r1"><span class="header-section-number">2.3</span> R1<a href="#r1" class="self-link"></a></h2>
<ul>
<li>Minor modifications</li>
</ul>
<h2 data-number="2.4" id="r0"><span class="header-section-number">2.4</span> R0<a href="#r0" class="self-link"></a></h2>
<ul>
<li>first revision</li>
</ul>
<h1 data-number="3" id="introduction"><span class="header-section-number">3</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p><span class="citation" data-cites="P2300">[<a href="#ref-P2300" role="doc-biblioref">P2300</a>]</span> describes a rounded set of primitives for asynchronous and parallel execution that give a firm grounding for the future. However, the paper lacks a standard execution context and scheduler. It has been broadly accepted that we need some sort of standard scheduler.</p>
<p>As noted in <span class="citation" data-cites="P2079R1">[<a href="#ref-P2079R1" role="doc-biblioref">P2079R1</a>]</span>, an earlier revision of this paper, the <code class="sourceCode default">static_thread_pool</code> included in later revisions of <span class="citation" data-cites="P0443">[<a href="#ref-P0443" role="doc-biblioref">P0443</a>]</span> had many shortcomings. This was removed from <span class="citation" data-cites="P2300">[<a href="#ref-P2300" role="doc-biblioref">P2300</a>]</span> based on that and other input.</p>
<p>This revision updates <span class="citation" data-cites="P2079R1">[<a href="#ref-P2079R1" role="doc-biblioref">P2079R1</a>]</span> to match the structure of <span class="citation" data-cites="P2300">[<a href="#ref-P2300" role="doc-biblioref">P2300</a>]</span>. It aims to provide a simple, flexible, standard execution context that should be used as the basis for examples but should also scale for practical use cases. It is a minimal design, with few constraints, and as such should be efficient to implement on top of something like a static thread pool, but also on top of system thread pools where fixing the number of threads diverges from efficient implementation goals.</p>
<p>Unlike in earlier verisons of this paper, we do not provide support for waiting on groups of tasks, delegating that to the separate <code class="sourceCode default">async_scope</code> design in <span class="citation" data-cites="P2519">[<a href="#ref-P2519" role="doc-biblioref">P2519R0</a>]</span>, because that is not functionality specific to a system context. Lifetime management in general should be considered delegated to <code class="sourceCode default">async_scope</code>.</p>
<p>The system context is of undefined size, supporting explicitly <em>parallel forward progress</em>. By requiring only parallel forward progress, any created parallel context is able to be a view onto the underlying shared global context. All instances of the <code class="sourceCode default">system_context</code> share the same underlying execution context. If the underlying context is a static thread pool, then all <code class="sourceCode default">system_context</code>s should reference that same static thread pool. This is important to ensure that applications can rely on constructing <code class="sourceCode default">system_context</code>s as necessary, without spawning an ever increasing number of threads. It also means that there is no isolation between <code class="sourceCode default">system_context</code> instances, which people should be aware of when they use this functionality. Note that if they rely strictly on parallel forward progress, this is not a problem, and is generally a safe way to develop applications.</p>
<p>The minimal extensions to basic parallel forward progress are to support fundamental functionality that is necessary to make parallel algorithms work:</p>
<ul>
<li>Cancellation: work submitted through the parallel context must be cancellable.</li>
<li>Forward progress delegation: we must be able to implement a blocking operation that ensures forward progress of a complex parallel algorithm without special cases.</li>
</ul>
<p>An implementation of <code class="sourceCode default">system_context</code> <em>should</em> allow link-time or compile-time replacement of the implementation such that the context may be replaced with an implementation that compiles and runs in a single-threaded process or that can be replaced with an appropriately configured system thread pool by an end-user. We do not attempt to specify here the mechanism by which this should be implemented.</p>
<p>Early feedback on the paper from Sean Parent suggested a need to allow the system context to carry no threads of its own, and take over the main thread. While in <span class="citation" data-cites="P2079R2">[<a href="#ref-P2079R2" role="doc-biblioref">P2079R2</a>]</span> we proposed <code class="sourceCode default">execute_chunk</code> and <code class="sourceCode default">execute_all</code>, these enforce a particular implementation on the underlying execution context. Instead we simplify the proposal by removing this functionality and assume that it is implemented by link-time or compile-time replacement of the context. We assume that the underlying mechanism to drive the context, should one be necessary, is implementation-defined. This allows custom hooks for an OS thread pool, or a simple <code class="sourceCode default">drive()</code> method in main.</p>
<h1 data-number="4" id="design"><span class="header-section-number">4</span> Design<a href="#design" class="self-link"></a></h1>
<h2 data-number="4.1" id="system_context"><span class="header-section-number">4.1</span> system_context<a href="#system_context" class="self-link"></a></h2>
<p>The <code class="sourceCode default">system_context</code> creates a view on some underlying execution context supporting <em>parallel forward progress</em>. A <code class="sourceCode default">system_context</code> must outlive any work launched on it.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">class</span> system_context <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb1-3"><a href="#cb1-3"></a>  system_context<span class="op">()</span>;</span>
<span id="cb1-4"><a href="#cb1-4"></a>   <span class="op">~</span>system_context<span class="op">()</span>;</span>
<span id="cb1-5"><a href="#cb1-5"></a></span>
<span id="cb1-6"><a href="#cb1-6"></a>  system_context<span class="op">(</span><span class="kw">const</span> system_context<span class="op">&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb1-7"><a href="#cb1-7"></a>  system_context<span class="op">(</span>system_context<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb1-8"><a href="#cb1-8"></a>  system_context<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span><span class="kw">const</span> system_context<span class="op">&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb1-9"><a href="#cb1-9"></a>  system_context<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span>system_context<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb1-10"><a href="#cb1-10"></a></span>
<span id="cb1-11"><a href="#cb1-11"></a>  implementation<span class="op">-</span>defined<span class="op">-</span>system_scheduler get_scheduler<span class="op">()</span>;</span>
<span id="cb1-12"><a href="#cb1-12"></a>  <span class="dt">size_t</span> max_concurrency<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb1-13"><a href="#cb1-13"></a><span class="op">}</span>;</span></code></pre></div>
<ul>
<li>On construction, the <code class="sourceCode default">system_context</code> may initialize a shared system context, if it has not been previously initialized.</li>
<li>To support sharing of an underlying system context, two <code class="sourceCode default">system_context</code> objects do not guarantee task isolation. If work submitted by one can consume the thread pool, that can block progress of another.</li>
<li>The <code class="sourceCode default">system_context</code> is non-copyable and non-moveable.</li>
<li>The <code class="sourceCode default">system_context</code> must outlive work launched on it. If there is outstanding work at the point of destruction, <code class="sourceCode default">std::terminate</code> will be called.</li>
<li>The <code class="sourceCode default">system_context</code> must outlive schedulers obtained from it. If there are outstanding schedulers at destruction time, this is undefined behavior.</li>
<li><code class="sourceCode default">get_scheduler</code> returns a <code class="sourceCode default">system_scheduler</code> instance that holds a reference to the <code class="sourceCode default">system_context</code>.</li>
<li><code class="sourceCode default">max_concurrency</code> will return a value representing the maximum number of threads the context may support. This is not a snapshot of the current number of threads, and may return <code class="sourceCode default">numeric_limits&lt;size_t&gt;::max</code>.</li>
</ul>
<h2 data-number="4.2" id="system_scheduler"><span class="header-section-number">4.2</span> system_scheduler<a href="#system_scheduler" class="self-link"></a></h2>
<p>A <code class="sourceCode default">system_scheduler</code> is a copyable handle to a <code class="sourceCode default">system_context</code>. It is the means through which agents are launched on a <code class="sourceCode default">system_context</code>. The <code class="sourceCode default">system_scheduler</code> instance does not have to outlive work submitted to it. The <code class="sourceCode default">system_scheduler</code> is technically implementation-defined, but must be nameable. See later discussion for how this might work.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">class</span> implementation<span class="op">-</span>defined<span class="op">-</span>system_scheduler <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb2-3"><a href="#cb2-3"></a>  system_scheduler<span class="op">()</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb2-4"><a href="#cb2-4"></a>  <span class="op">~</span>system_scheduler<span class="op">()</span>;</span>
<span id="cb2-5"><a href="#cb2-5"></a></span>
<span id="cb2-6"><a href="#cb2-6"></a>  system_scheduler<span class="op">(</span><span class="kw">const</span> system_scheduler<span class="op">&amp;)</span>;</span>
<span id="cb2-7"><a href="#cb2-7"></a>  system_scheduler<span class="op">(</span>system_scheduler<span class="op">&amp;&amp;)</span>;</span>
<span id="cb2-8"><a href="#cb2-8"></a>  system_scheduler<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span><span class="kw">const</span> system_scheduler<span class="op">&amp;)</span>;</span>
<span id="cb2-9"><a href="#cb2-9"></a>  system_scheduler<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span>system_scheduler<span class="op">&amp;&amp;)</span>;</span>
<span id="cb2-10"><a href="#cb2-10"></a></span>
<span id="cb2-11"><a href="#cb2-11"></a>  <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span><span class="kw">const</span> system_scheduler<span class="op">&amp;)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb2-12"><a href="#cb2-12"></a></span>
<span id="cb2-13"><a href="#cb2-13"></a>  <span class="kw">friend</span> implementation<span class="op">-</span>defined<span class="op">-</span>system_sender tag_invoke<span class="op">(</span></span>
<span id="cb2-14"><a href="#cb2-14"></a>    std<span class="op">::</span>execution<span class="op">::</span>schedule_t, <span class="kw">const</span> implementation<span class="op">-</span>defined<span class="op">-</span>system_scheduler<span class="op">&amp;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb2-15"><a href="#cb2-15"></a>  <span class="kw">friend</span> std<span class="op">::</span>execution<span class="op">::</span>forward_progress_guarantee tag_invoke<span class="op">(</span></span>
<span id="cb2-16"><a href="#cb2-16"></a>    std<span class="op">::</span>execution<span class="op">::</span>get_forward_progress_guarantee_t,</span>
<span id="cb2-17"><a href="#cb2-17"></a>    <span class="kw">const</span> system_scheduler<span class="op">&amp;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb2-18"><a href="#cb2-18"></a>  <span class="kw">friend</span> implementation<span class="op">-</span>defined<span class="op">-</span>bulk<span class="op">-</span>sender tag_invoke<span class="op">(</span></span>
<span id="cb2-19"><a href="#cb2-19"></a>    std<span class="op">::</span>execution<span class="op">::</span>bulk_t,</span>
<span id="cb2-20"><a href="#cb2-20"></a>    <span class="kw">const</span> system_scheduler<span class="op">&amp;</span>,</span>
<span id="cb2-21"><a href="#cb2-21"></a>    Sh<span class="op">&amp;&amp;</span> sh,</span>
<span id="cb2-22"><a href="#cb2-22"></a>    F<span class="op">&amp;&amp;</span> f<span class="op">)</span> <span class="kw">noexcept</span>;</span>
<span id="cb2-23"><a href="#cb2-23"></a><span class="op">}</span>;</span></code></pre></div>
<ul>
<li><code class="sourceCode default">system_scheduler</code> is not independely constructable, and must be obtained from a <code class="sourceCode default">system_context</code>. It is both move and copy constructable and assignable.</li>
<li>Two <code class="sourceCode default">system_scheduler</code>s compare equal if they share the same underlying <code class="sourceCode default">system_context</code>.</li>
<li>A <code class="sourceCode default">system_scheduler</code> has reference semantics with respect to its <code class="sourceCode default">system_context</code>. Calling any operation other than the destructor on a <code class="sourceCode default">system_scheduler</code> after the <code class="sourceCode default">system_context</code> it was created from is destroyed is undefined behavior, and that operation may access freed memory.</li>
<li>The <code class="sourceCode default">system_scheduler</code>:
<ul>
<li>satisfies the <code class="sourceCode default">scheduler</code> concept and implements the <code class="sourceCode default">schedule</code> customisation point to return an <code class="sourceCode default">implementation-defined</code> <code class="sourceCode default">sender</code> type.</li>
<li>implements the <code class="sourceCode default">get_forward_progress_guarantee</code> query to return <code class="sourceCode default">parallel</code>.</li>
<li>implements the <code class="sourceCode default">bulk</code> CPO to customise the <code class="sourceCode default">bulk</code> sender adapter such that:
<ul>
<li>When <code class="sourceCode default">execution::set_value(r, args...)</code> is called on the created <code class="sourceCode default">receiver</code>, an agent is created with parallel forward progress on the underlying <code class="sourceCode default">system_context</code> for each <code class="sourceCode default">i</code> of type <code class="sourceCode default">Shape</code> from <code class="sourceCode default">0</code> to <code class="sourceCode default">sh</code>, where <code class="sourceCode default">sh</code> is the shape parameter to the bulk call, that calls <code class="sourceCode default">f(i, args...)</code>.</li>
</ul></li>
</ul></li>
<li><code class="sourceCode default">schedule</code> calls on a <code class="sourceCode default">system_scheduler</code> are non-blocking operations.</li>
<li>If the underlying <code class="sourceCode default">system_context</code> is unable to make progress on work created through <code class="sourceCode default">system_scheduler</code> instances, and the sender retrieved from <code class="sourceCode default">scheduler</code> is connected to a <code class="sourceCode default">receiver</code> that supports the <code class="sourceCode default">get_delegatee_scheduler</code> query, work may scheduled on the <code class="sourceCode default">scheduler</code> returned by <code class="sourceCode default">get_delegatee_scheduler</code> at the time of the call to <code class="sourceCode default">start</code>, or at any later point before the work completes.</li>
</ul>
<h2 data-number="4.3" id="system-sender"><span class="header-section-number">4.3</span> system sender<a href="#system-sender" class="self-link"></a></h2>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1"></a><span class="kw">class</span> implementation<span class="op">-</span>defined<span class="op">-</span>system_sender <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb3-3"><a href="#cb3-3"></a>  <span class="kw">friend</span> pair<span class="op">&lt;</span>std<span class="op">::</span>execution<span class="op">::</span>system_scheduler, delegatee_scheduler<span class="op">&gt;</span> tag_invoke<span class="op">(</span></span>
<span id="cb3-4"><a href="#cb3-4"></a>    std<span class="op">::</span>execution<span class="op">::</span>get_completion_scheduler_t<span class="op">&lt;</span>set_value_t<span class="op">&gt;</span>,</span>
<span id="cb3-5"><a href="#cb3-5"></a>    <span class="kw">const</span> system_scheduler<span class="op">&amp;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb3-6"><a href="#cb3-6"></a>  <span class="kw">friend</span> pair<span class="op">&lt;</span>std<span class="op">::</span>execution<span class="op">::</span>system_scheduler, delegatee_scheduler<span class="op">&gt;</span> tag_invoke<span class="op">(</span></span>
<span id="cb3-7"><a href="#cb3-7"></a>    std<span class="op">::</span>execution<span class="op">::</span>get_completion_scheduler_t<span class="op">&lt;</span>set_done_t<span class="op">&gt;</span>,</span>
<span id="cb3-8"><a href="#cb3-8"></a>    <span class="kw">const</span> system_scheduler<span class="op">&amp;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb3-9"><a href="#cb3-9"></a></span>
<span id="cb3-10"><a href="#cb3-10"></a>  <span class="kw">template</span><span class="op">&lt;</span>receiver R<span class="op">&gt;</span></span>
<span id="cb3-11"><a href="#cb3-11"></a>        <span class="kw">requires</span> receiver_of<span class="op">&lt;</span>R<span class="op">&gt;</span></span>
<span id="cb3-12"><a href="#cb3-12"></a>  <span class="kw">friend</span> implementation<span class="op">-</span>defined<span class="op">-</span>operation_state</span>
<span id="cb3-13"><a href="#cb3-13"></a>    tag_invoke<span class="op">(</span>execution<span class="op">::</span>connect_t, implementation<span class="op">-</span>defined<span class="op">-</span>system_sender<span class="op">&amp;&amp;</span>, R<span class="op">&amp;&amp;)</span>;</span>
<span id="cb3-14"><a href="#cb3-14"></a></span>
<span id="cb3-15"><a href="#cb3-15"></a>  <span class="op">...</span></span>
<span id="cb3-16"><a href="#cb3-16"></a><span class="op">}</span>;</span></code></pre></div>
<p><code class="sourceCode default">schedule</code> on a <code class="sourceCode default">system_scheduler</code> returns some implementation-defined <code class="sourceCode default">sender</code> type.</p>
<p>This sender satisfies the following properties:</p>
<ul>
<li>Implements the <code class="sourceCode default">get_completion_scheduler</code> query for the value and done channel where it returns a type that is logically a pair of an object that compares equal to itself, and a representation of delegatee scheduler that may be obtained from receivers connected with the sender.</li>
<li>If connected with a <code class="sourceCode default">receiver</code> that supports the <code class="sourceCode default">get_stop_token</code> query, if that <code class="sourceCode default">stop_token</code> is stopped, operations on which <code class="sourceCode default">start</code> has been called, but are not yet running (and are hence not yet guaranteed to make progress) <strong>must</strong> complete with <code class="sourceCode default">set_done</code> as soon as is practical.</li>
<li><code class="sourceCode default">connect</code>ing the <code class="sourceCode default">sender</code> and calling <code class="sourceCode default">start()</code> on the resulting operation state are non-blocking operations.</li>
</ul>
<h1 data-number="5" id="design-discussion-and-decisions"><span class="header-section-number">5</span> Design discussion and decisions<a href="#design-discussion-and-decisions" class="self-link"></a></h1>
<h2 data-number="5.1" id="to-drive-or-not-to-drive"><span class="header-section-number">5.1</span> To drive or not to drive<a href="#to-drive-or-not-to-drive" class="self-link"></a></h2>
<p>The earlier version of this paper, <span class="citation" data-cites="P2079R2">[<a href="#ref-P2079R2" role="doc-biblioref">P2079R2</a>]</span>, included <code class="sourceCode default">execute_all</code> and <code class="sourceCode default">execute_chunk</code> operations to integrate with senders. In this version we have removed them because they imply certain requirements of forward progress delegation on the system context and it is not clear whether or not they should be called.</p>
<p>It is still an open question whether or not having such a standard operation makes the system context more or less portable. We can simplify this discussion to a single function:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb4-1"><a href="#cb4-1"></a>  void drive(system_context&amp; ctx, sender auto snd);</span></code></pre></div>
<p>Let’s assume we have a single-threaded environment, and a means of customising the <code class="sourceCode default">system_context</code> for this environment. We know we need a way to donate <code class="sourceCode default">main</code>’s thread to this context, it is the only thread we have available. Assuming that we want a <code class="sourceCode default">drive</code> operation in some form, our choices are to:</p>
<ul>
<li>define our <code class="sourceCode default">drive</code> operation, so that it is standard, and we use it on this system.</li>
<li>or allow the customisation to define a custom <code class="sourceCode default">drive</code> operation related to the specific single-threaded environment.</li>
</ul>
<p>With a standard <code class="sourceCode default">drive</code> of this sort (or of the more complex design in <span class="citation" data-cites="P2079R2">[<a href="#ref-P2079R2" role="doc-biblioref">P2079R2</a>]</span>) we might write an example to use it directly:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a>system_context ctx;</span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="kw">auto</span> snd <span class="op">=</span> on<span class="op">(</span>ctx, doWork<span class="op">())</span>;</span>
<span id="cb5-3"><a href="#cb5-3"></a>drive<span class="op">(</span>ctx, std<span class="op">::</span>move<span class="op">(</span>snd<span class="op">))</span>;</span></code></pre></div>
<p>Without drive, we rely on an <code class="sourceCode default">async_scope</code> to spawn the work and some system-specific drive operation:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a>system_context ctx;</span>
<span id="cb6-2"><a href="#cb6-2"></a>async_scope scope;</span>
<span id="cb6-3"><a href="#cb6-3"></a><span class="kw">auto</span> snd <span class="op">=</span> on<span class="op">(</span>ctx, doWork<span class="op">())</span>;</span>
<span id="cb6-4"><a href="#cb6-4"></a>scope<span class="op">.</span>spawn<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>snd<span class="op">))</span>;</span>
<span id="cb6-5"><a href="#cb6-5"></a>custom_drive_operation<span class="op">(</span>ctx<span class="op">)</span>;</span></code></pre></div>
<p>The question is: what is more portable? It seems at first sight that a general <code class="sourceCode default">drive</code> function is more portable. Without it, how can we write a fully portable “hello world” example?</p>
<p>More broadly, it may not be more portable. First, we don’t know whether or not we need to call it. Whether that drive call is needed is a function of whether the environment is single threaded or not. If it is not, say we have a normal Windows system with threads, we simply don’t need to call it and the thread pool may not even have a way to process the donated <code class="sourceCode default">main</code> thread.</p>
<p>Further, we don’t know the full set of single threaded environments. If this is a UI we may not want <code class="sourceCode default">main</code> to call the <code class="sourceCode default">system_context</code>’s drive, but rather that it will drive some UI event loop directly and <code class="sourceCode default">system_context</code> is simply a window to add tasks to that event loop. <code class="sourceCode default">drive</code> in this context is a confusing complication and might be harmful.</p>
<p>From the other angle, is an entirely custom <code class="sourceCode default">drive</code> operation, pulled in through whatever mechanism we have for swapping out the <code class="sourceCode default">system_context</code> portable? Most systems will not need such a function to be called. We do not in general need to on Windows, Linux, MacOS and similar systems with thread pool support. When we do need it, we have explicitly opted in to compiling or linking against a specific implementation of the <code class="sourceCode default">system_context</code> for the environment in question. On that basis, given the amount of other work we’d have to do to make the system work, like driving the UI loop, the small addition of also driving the <code class="sourceCode default">system_context</code> seems minor.</p>
<p>The authors recommendation here is that we allow <code class="sourceCode default">drive</code> to be unspecified in the standard, and to appear as a result of customisation of the system context where needed. However, this is a question we should answer.</p>
<h2 data-number="5.2" id="making-system_context-implementation-defined"><span class="header-section-number">5.2</span> Making system_context implementation-defined<a href="#making-system_context-implementation-defined" class="self-link"></a></h2>
<p>The system context aims to allow people to implement an application that is dependent only on parallel forward progress and to port it to a wide range of systems. As long as an application does not rely on concurrency, and restricts itself to only the system context, we should be able to scale from single threaded systems to highly parallel systems.</p>
<p>In the extreme, this might mean porting to an embedded system with a very specific idea of an execution context. Such a system might not have a multi-threading support at all, and thus the system context not only need run with single thread, but actually run on the system’s only thread. We might build the context on top of a UI thread, or we might want to swap out the system-provided implementation with one from a vendor like Intel with experience writing optimised threading runtimes.</p>
<p>We need to allow customisation of the system context to cover this full range of cases. For a whole platform this is relatively simple. We assume that everything is an implementation-defined type. The <code class="sourceCode default">system_context</code> itself is a named type, but in practice is implementation-defined, in the same way that <code class="sourceCode default">std::vector</code> is implementation-defined at the platform level.</p>
<p>Other situations may offer a little less control. If we wish Intel to be able to replace the system thread pool with TBB, or Adobe to customise the runtime that they use for all of Photoshop to adapt to their needs, we need a different customisation mechanism.</p>
<p>To achieve this we see options:</p>
<ul>
<li>Link-time replaceability. This could be achieved using weak symbols, or by chosing a runtime library to pull in using build options.</li>
<li>Compile-time replacability. This could be achieved by importing different headers, by macro definitions on the command line or various other mechanisms.</li>
<li>Run-time replaceability. This could be achieved by subclassing and requiring certain calls to be made early in the process.</li>
</ul>
<p>Link-time replaceability is more predictable, in that it can be guaranteed to be application-global. The downside of link-time replaceability is that it requires defining the ABI and thus would require significant type erasure and inefficiency. Some of that ineffienciency can be removed in practice with link-time optimisation.</p>
<p>Compile-time is simpler but would be easy to get wrong by mixing flags across the objects in the build. Both link-time and compile-time maybe difficult to describe in the standard.</p>
<p>Run-time is easy for us to describe in the standard, using interfaces and dynamic dispatch with well-defined mechanisms for setting the implementation. The downsides are that it is hard to ensure that the right context is set early enough in the process and that, like link-time replacement, it requires type erasure.</p>
<p>The other question is to what extent we need to specify this. We could simply say that implementations should allow customization and leave it up to QOI. We already know that full platform customisations are possible. This approach would delegate the decision of how to allow Intel to replace the platform context with TBB up to the platform implementor. It would rely on an agreement between the system vendor and the runtime vendor.</p>
<p>The authors do not have a recommendation, only a wish to see customisation available. We should decide how best to achieve it within the standard. Assuming we delegate customisation to the platform implementor, what wording would be appropriate for the specification, if any?</p>
<h2 data-number="5.3" id="need-for-the-system_context-class"><span class="header-section-number">5.3</span> Need for the system_context class<a href="#need-for-the-system_context-class" class="self-link"></a></h2>
<p>Our goal is to expose a global shared context to avoid oversubscription of threads in the system and to efficiently share a system thread pool. Underneath the <code class="sourceCode default">system_context</code> there is a singleton of some sort, potentially owned by the OS.</p>
<p>The question is how we expose the singleton. We have a few obvious options:</p>
<ul>
<li>Explicit context objects, as we’ve described in R2 and R3 of this paper, where a <code class="sourceCode default">system_context</code> is constructed as any other context might be, and refers to a singleton underneath.</li>
<li>A global <code class="sourceCode default">get_system_context()</code> function that obtains a <code class="sourceCode default">system_context</code> object, or a reference to one, representing the singleton explicitly.</li>
<li>A global <code class="sourceCode default">get_system_scheduler()</code> function that obtains a scheduler from some singleton system context, but does not explicitly expose the context.</li>
</ul>
<p>The <code class="sourceCode default">get_system_context()</code> function returning by value adds little, it’s equivalent to direct construction. <code class="sourceCode default">get_system_context()</code> returning by reference and <code class="sourceCode default">get_system_scheduler()</code> have a different lifetime semantic from directly constructed <code class="sourceCode default">system_context</code>.</p>
<p>The main reason for having an explicit by-value context is that we can reason about lifetimes. If we only have schedulers, from <code class="sourceCode default">get_system_context().get_scheduler()</code> or from <code class="sourceCode default">get_system_scheduler()</code> then we have to think about how they affect the context lifetime. We might want to reference count the context, to ensure it outlives the schedulers, but this adds cost to each scheduler use, and to any downstream sender produced from the scheduler as well that is logically dependent on the scheduler. We could alternatively not reference count and assume the context outlives everything in the system, but that leads quickly to shutdown order questions and potential surprises.</p>
<p>By making the context explicit we require users to drain their work before they drain the context. In debug builds, at least, we can also add reference counting so that descruction of the context before work completes reports a clear error to ensure that people clean up. That is harder to do if the context is destroyed at some point after main completes. This lifetime question also applies to construction: we can lazily construct a thread pool before we first use a scheduler to it.</p>
<p>For this reason, and consistency with other discussions about structured concurrency, we opt for an explicit context object here.</p>
<h2 data-number="5.4" id="priorities"><span class="header-section-number">5.4</span> Priorities<a href="#priorities" class="self-link"></a></h2>
<p>It’s broadly accepted that we need some form of priorities to tweak the behaviour of the system context. This paper does not include priorities, though early drafts of R2 did. We had different designs in flight for how to achieve priorities and decided they could be added later in either approach.</p>
<p>The first approach is to expand one or more of the APIs. The obvious way to do this would be to add a priority-taking version of <code class="sourceCode default">system_context::get_scheduler()</code>:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1"></a>implementation<span class="op">-</span>defined<span class="op">-</span>system_scheduler get_scheduler<span class="op">()</span>;</span>
<span id="cb7-2"><a href="#cb7-2"></a>implementation<span class="op">-</span>defined<span class="op">-</span>system_scheduler get_scheduler<span class="op">(</span>priority_t priority<span class="op">)</span>;</span></code></pre></div>
<p>This approach would offer priorities at scheduler granularity and apply to large sections of a program at once.</p>
<p>The other approach, which matches the receiver query approach taken elsewhere in <span class="citation" data-cites="P2300">[<a href="#ref-P2300" role="doc-biblioref">P2300</a>]</span> is to add a <code class="sourceCode default">get_priority()</code> query on the receiver, which, if available, passes a priority to the scheduler in the same way that we pass an <code class="sourceCode default">allocator</code> or a <code class="sourceCode default">stop_token</code>. This would work at task granularity, for each <code class="sourceCode default">schedule()</code> call that we connect a receiver to we might pass a different priority.</p>
<p>In either case we can add the priority in a separate paper. It is thus not urgent that we answer this question, but we include the discussion point to explain why they were removed from the paper.</p>
<h1 data-number="6" id="examples"><span class="header-section-number">6</span> Examples<a href="#examples" class="self-link"></a></h1>
<p>As a simple parallel scheduler we can use it locally, and <code class="sourceCode default">sync_wait</code> on the work to make sure that it is complete. With forward progress delegation this would also allow the scheduler to delegate work to the blocked thread. This example is derived from the Hello World example in <span class="citation" data-cites="P2300">[<a href="#ref-P2300" role="doc-biblioref">P2300</a>]</span>. Note that it only adds a well-defined context object, and queries that for the scheduler. Everything else is unchanged about the example.</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1"></a><span class="kw">using</span> <span class="kw">namespace</span> std<span class="op">::</span>execution;</span>
<span id="cb8-2"><a href="#cb8-2"></a></span>
<span id="cb8-3"><a href="#cb8-3"></a>system_context ctx;</span>
<span id="cb8-4"><a href="#cb8-4"></a>scheduler <span class="kw">auto</span> sch <span class="op">=</span> ctx<span class="op">.</span>scheduler<span class="op">()</span>;</span>
<span id="cb8-5"><a href="#cb8-5"></a></span>
<span id="cb8-6"><a href="#cb8-6"></a>sender <span class="kw">auto</span> begin <span class="op">=</span> schedule<span class="op">(</span>sch<span class="op">)</span>;</span>
<span id="cb8-7"><a href="#cb8-7"></a>sender <span class="kw">auto</span> hi <span class="op">=</span> then<span class="op">(</span>begin, <span class="op">[]{</span></span>
<span id="cb8-8"><a href="#cb8-8"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;Hello world! Have an int.&quot;</span>;</span>
<span id="cb8-9"><a href="#cb8-9"></a>    <span class="cf">return</span> <span class="dv">13</span>;</span>
<span id="cb8-10"><a href="#cb8-10"></a><span class="op">})</span>;</span>
<span id="cb8-11"><a href="#cb8-11"></a>sender <span class="kw">auto</span> add_42 <span class="op">=</span> then<span class="op">(</span>hi, <span class="op">[](</span><span class="dt">int</span> arg<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> arg <span class="op">+</span> <span class="dv">42</span>; <span class="op">})</span>;</span>
<span id="cb8-12"><a href="#cb8-12"></a></span>
<span id="cb8-13"><a href="#cb8-13"></a><span class="kw">auto</span> <span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> this_thread<span class="op">::</span>sync_wait<span class="op">(</span>add_42<span class="op">).</span>value<span class="op">()</span>;</span></code></pre></div>
<p>We can structure the same thing using <code class="sourceCode default">execution::on</code>, which better matches structured concurrency:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1"></a><span class="kw">using</span> <span class="kw">namespace</span> std<span class="op">::</span>execution;</span>
<span id="cb9-2"><a href="#cb9-2"></a></span>
<span id="cb9-3"><a href="#cb9-3"></a>system_context ctx;</span>
<span id="cb9-4"><a href="#cb9-4"></a>scheduler <span class="kw">auto</span> sch <span class="op">=</span> ctx<span class="op">.</span>scheduler<span class="op">()</span>;</span>
<span id="cb9-5"><a href="#cb9-5"></a></span>
<span id="cb9-6"><a href="#cb9-6"></a>sender <span class="kw">auto</span> hi <span class="op">=</span> then<span class="op">(</span>just<span class="op">()</span>, <span class="op">[]{</span></span>
<span id="cb9-7"><a href="#cb9-7"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;Hello world! Have an int.&quot;</span>;</span>
<span id="cb9-8"><a href="#cb9-8"></a>    <span class="cf">return</span> <span class="dv">13</span>;</span>
<span id="cb9-9"><a href="#cb9-9"></a><span class="op">})</span>;</span>
<span id="cb9-10"><a href="#cb9-10"></a>sender <span class="kw">auto</span> add_42 <span class="op">=</span> then<span class="op">(</span>hi, <span class="op">[](</span><span class="dt">int</span> arg<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> arg <span class="op">+</span> <span class="dv">42</span>; <span class="op">})</span>;</span>
<span id="cb9-11"><a href="#cb9-11"></a></span>
<span id="cb9-12"><a href="#cb9-12"></a><span class="kw">auto</span> <span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> this_thread<span class="op">::</span>sync_wait<span class="op">(</span>on<span class="op">(</span>sch, add_42<span class="op">)).</span>value<span class="op">()</span>;</span></code></pre></div>
<p>The <code class="sourceCode default">system_scheduler</code> customises bulk, so we can use bulk dependent on the scheduler. Here we use it in structured form using the parameterless <code class="sourceCode default">get_scheduler</code> that retrieves the scheduler from the receiver, combined with <code class="sourceCode default">on</code>:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1"></a><span class="kw">auto</span> bar<span class="op">()</span> <span class="op">{</span></span>
<span id="cb10-2"><a href="#cb10-2"></a>  <span class="cf">return</span></span>
<span id="cb10-3"><a href="#cb10-3"></a>    ex<span class="op">::</span>let_value<span class="op">(</span></span>
<span id="cb10-4"><a href="#cb10-4"></a>      ex<span class="op">::</span>get_scheduler<span class="op">()</span>,          <span class="co">// Fetch scheduler from receiver.</span></span>
<span id="cb10-5"><a href="#cb10-5"></a>      <span class="op">[](</span><span class="kw">auto</span> current_sched<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-6"><a href="#cb10-6"></a>        <span class="cf">return</span> bulk<span class="op">(</span></span>
<span id="cb10-7"><a href="#cb10-7"></a>          current_sched<span class="op">.</span>schedule<span class="op">()</span>,</span>
<span id="cb10-8"><a href="#cb10-8"></a>          <span class="dv">1</span>,                        <span class="co">// Only 1 bulk task as a lazy way of making cout safe</span></span>
<span id="cb10-9"><a href="#cb10-9"></a>          <span class="op">[](</span><span class="kw">auto</span> idx<span class="op">){</span></span>
<span id="cb10-10"><a href="#cb10-10"></a>            std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;Index: &quot;</span> <span class="op">&lt;&lt;</span> idx <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb10-11"><a href="#cb10-11"></a>          <span class="op">})</span></span>
<span id="cb10-12"><a href="#cb10-12"></a>      <span class="op">})</span>;</span>
<span id="cb10-13"><a href="#cb10-13"></a><span class="op">}</span></span>
<span id="cb10-14"><a href="#cb10-14"></a></span>
<span id="cb10-15"><a href="#cb10-15"></a><span class="dt">void</span> foo<span class="op">()</span></span>
<span id="cb10-16"><a href="#cb10-16"></a><span class="op">{</span></span>
<span id="cb10-17"><a href="#cb10-17"></a>  <span class="kw">using</span> <span class="kw">namespace</span> std<span class="op">::</span>execution;</span>
<span id="cb10-18"><a href="#cb10-18"></a></span>
<span id="cb10-19"><a href="#cb10-19"></a>  system_context ctx;</span>
<span id="cb10-20"><a href="#cb10-20"></a></span>
<span id="cb10-21"><a href="#cb10-21"></a>  <span class="kw">auto</span> <span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> this_thread<span class="op">::</span>sync_wait<span class="op">(</span></span>
<span id="cb10-22"><a href="#cb10-22"></a>    on<span class="op">(</span></span>
<span id="cb10-23"><a href="#cb10-23"></a>      ctx<span class="op">.</span>scheduler<span class="op">()</span>,                <span class="co">// Start bar on the system_scheduler</span></span>
<span id="cb10-24"><a href="#cb10-24"></a>      bar<span class="op">()))</span>                         <span class="co">// and propagate it through the receivers</span></span>
<span id="cb10-25"><a href="#cb10-25"></a>    <span class="op">.</span>value<span class="op">()</span>;</span>
<span id="cb10-26"><a href="#cb10-26"></a><span class="op">}</span></span></code></pre></div>
<p>Use <code class="sourceCode default">async_scope</code> and a custom system context implementation linked in to the process (through a mechanism undefined in the example). This might be how a given platform exposes a custom context. In this case we assume it has no threads of its own and has to take over the main thread through an custom <code class="sourceCode default">drive()</code> operation that can be looped until a callback requests <code class="sourceCode default">exit</code> on the context.</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1"></a><span class="kw">using</span> <span class="kw">namespace</span> std<span class="op">::</span>execution;</span>
<span id="cb11-2"><a href="#cb11-2"></a></span>
<span id="cb11-3"><a href="#cb11-3"></a>system_context ctx;</span>
<span id="cb11-4"><a href="#cb11-4"></a></span>
<span id="cb11-5"><a href="#cb11-5"></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"></a></span>
<span id="cb11-7"><a href="#cb11-7"></a><span class="op">{</span></span>
<span id="cb11-8"><a href="#cb11-8"></a>  async_scope scope;</span>
<span id="cb11-9"><a href="#cb11-9"></a>  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-10"><a href="#cb11-10"></a></span>
<span id="cb11-11"><a href="#cb11-11"></a>  sender <span class="kw">auto</span> work <span class="op">=</span></span>
<span id="cb11-12"><a href="#cb11-12"></a>    then<span class="op">(</span>just<span class="op">()</span>, <span class="op">[&amp;](</span><span class="kw">auto</span> sched<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-13"><a href="#cb11-13"></a></span>
<span id="cb11-14"><a href="#cb11-14"></a>      <span class="dt">int</span> val <span class="op">=</span> <span class="dv">13</span>;</span>
<span id="cb11-15"><a href="#cb11-15"></a></span>
<span id="cb11-16"><a href="#cb11-16"></a>      <span class="kw">auto</span> print_sender <span class="op">=</span> then<span class="op">(</span>just<span class="op">()</span>, <span class="op">[</span>val<span class="op">]{</span></span>
<span id="cb11-17"><a href="#cb11-17"></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-18"><a href="#cb11-18"></a>      <span class="op">})</span>;</span>
<span id="cb11-19"><a href="#cb11-19"></a></span>
<span id="cb11-20"><a href="#cb11-20"></a>      <span class="co">// spawn the print sender on sched to make sure it</span></span>
<span id="cb11-21"><a href="#cb11-21"></a>      <span class="co">// completes before shutdown</span></span>
<span id="cb11-22"><a href="#cb11-22"></a>      scope<span class="op">.</span>spawn<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>;</span>
<span id="cb11-23"><a href="#cb11-23"></a></span>
<span id="cb11-24"><a href="#cb11-24"></a>      <span class="cf">return</span> val;</span>
<span id="cb11-25"><a href="#cb11-25"></a>    <span class="op">})</span>;</span>
<span id="cb11-26"><a href="#cb11-26"></a></span>
<span id="cb11-27"><a href="#cb11-27"></a>  scope<span class="op">.</span>spawn<span class="op">(</span>on<span class="op">(</span>sch, std<span class="op">::</span>move<span class="op">(</span>work<span class="op">)))</span>;</span>
<span id="cb11-28"><a href="#cb11-28"></a></span>
<span id="cb11-29"><a href="#cb11-29"></a>  <span class="co">// This is custom code for a single-threaded context that we have replaced</span></span>
<span id="cb11-30"><a href="#cb11-30"></a>  <span class="co">// at compile-time (see discussion options).</span></span>
<span id="cb11-31"><a href="#cb11-31"></a>  <span class="co">// We need to drive it in main.</span></span>
<span id="cb11-32"><a href="#cb11-32"></a>  <span class="co">// It is not directly sender-aware, like any pre-existing work loop, but</span></span>
<span id="cb11-33"><a href="#cb11-33"></a>  <span class="co">// does provide an exit operation. We may call this from a callback chained</span></span>
<span id="cb11-34"><a href="#cb11-34"></a>  <span class="co">// after the scope becomes empty.</span></span>
<span id="cb11-35"><a href="#cb11-35"></a>  <span class="co">// We use a temporary terminal_scope here to separate the shut down</span></span>
<span id="cb11-36"><a href="#cb11-36"></a>  <span class="co">// operation and block for it at the end of main, knowing it will complete.</span></span>
<span id="cb11-37"><a href="#cb11-37"></a>  async_scope terminal_scope;</span>
<span id="cb11-38"><a href="#cb11-38"></a>  terminal_scope<span class="op">.</span>spawn<span class="op">(</span></span>
<span id="cb11-39"><a href="#cb11-39"></a>    scope<span class="op">.</span>on_empty<span class="op">()</span> <span class="op">|</span> then<span class="op">([](</span>my_os<span class="op">::</span>exit<span class="op">(</span>ctx<span class="op">))))</span>;</span>
<span id="cb11-40"><a href="#cb11-40"></a>  my_os<span class="op">::</span>drive<span class="op">(</span>ctx<span class="op">)</span>;</span>
<span id="cb11-41"><a href="#cb11-41"></a>  this_thread<span class="op">::</span>sync_wait<span class="op">(</span>terminal_scope<span class="op">)</span>;</span>
<span id="cb11-42"><a href="#cb11-42"></a><span class="op">}</span>;</span>
<span id="cb11-43"><a href="#cb11-43"></a></span>
<span id="cb11-44"><a href="#cb11-44"></a><span class="co">// The scope ensured that all work is safely joined, so result contains 13</span></span>
<span id="cb11-45"><a href="#cb11-45"></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-46"><a href="#cb11-46"></a></span>
<span id="cb11-47"><a href="#cb11-47"></a><span class="co">// and destruction of the context is now safe</span></span></code></pre></div>
<h1 data-number="7" id="bibliography"><span class="header-section-number">7</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references hanging-indent" role="doc-bibliography">
<div id="ref-P0443">
<p>[P0443] 2020. A Unified Executors Proposal for C++. <br />
<a href="https://wg21.link/p0443">https://wg21.link/p0443</a></p>
</div>
<div id="ref-P2079R1">
<p>[P2079R1] Ruslan Arutyunyan, Michael Voss. 2020-08-15. Parallel Executor. <br />
<a href="https://wg21.link/p2079r1">https://wg21.link/p2079r1</a></p>
</div>
<div id="ref-P2079R2">
<p>[P2079R2] Lee Howes, Ruslan Arutyunyan, Michael Voss. 2022-01-15. System execution context. <br />
<a href="https://wg21.link/p2079r2">https://wg21.link/p2079r2</a></p>
</div>
<div id="ref-P2300">
<p>[P2300] 2022. std::execution. <br />
<a href="https://wg21.link/p2300">https://wg21.link/p2300</a></p>
</div>
<div id="ref-P2519">
<p>[P2519R0] 2022. async_scope - Creating scopes for non-sequential concurrency. <br />
<a href="https://wg21.link/p2519">https://wg21.link/p2519</a></p>
</div>
</div>
</div>
</div>
</body>
</html>
