4<!DOCTYPE html>

<html lang="en">

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="mobile-web-app-capable" content="yes">
    <title>
        Improving C++ concurrency features
    </title>
    <link rel="icon" type="image/ico" href="https://isocpp.org/favicon.ico">

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css" integrity="sha256-3iu9jgsy9TpTwXKb7bNQzqWekRX7pPK+2OLj3R922fo=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/octicons/3.5.0/octicons.min.css" integrity="sha256-QiWfLIsCT02Sdwkogf6YMiQlj4NE84MKkzEMkZnMGdg=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/themes/prism.min.css" integrity="sha256-vtR0hSWRc3Tb26iuN2oZHt3KRUomwTufNIf5/4oeCyg=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@hackmd/emojify.js@2.1.0/dist/css/basic/emojify.min.css" integrity="sha256-UOrvMOsSDSrW6szVLe8ZDZezBxh5IoIfgTwdNDgTjiU=" crossorigin="anonymous" />
    <style>
        @import url(https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500,500i|Source+Code+Pro:300,400,500|Source+Sans+Pro:300,300i,400,400i,600,600i|Source+Serif+Pro&subset=latin-ext);.hljs{background:#fff;color:#333;display:block;overflow-x:auto;padding:.5em}.hljs-comment,.hljs-meta{color:#969896}.hljs-emphasis,.hljs-quote,.hljs-string,.hljs-strong,.hljs-template-variable,.hljs-variable{color:#df5000}.hljs-keyword,.hljs-selector-tag,.hljs-type{color:#a71d5d}.hljs-attribute,.hljs-bullet,.hljs-literal,.hljs-number,.hljs-symbol{color:#0086b3}.hljs-built_in,.hljs-builtin-name{color:#005cc5}.hljs-name,.hljs-section{color:#63a35c}.hljs-tag{color:#333}.hljs-attr,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-title{color:#795da3}.hljs-addition{background-color:#eaffea;color:#55a532}.hljs-deletion{background-color:#ffecec;color:#bd2c00}.hljs-link{text-decoration:underline}.markdown-body{word-wrap:break-word;font-size:16px;line-height:1.5}.markdown-body:after,.markdown-body:before{content:"";display:table}.markdown-body:after{clear:both}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body .absent{color:#c00}.markdown-body .anchor{float:left;line-height:1;margin-left:-20px;padding-right:4px}.markdown-body .anchor:focus{outline:none}.markdown-body blockquote,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-bottom:16px;margin-top:0}.markdown-body hr{background-color:#e7e7e7;border:0;height:.25em;margin:24px 0;padding:0}.markdown-body blockquote{border-left:.25em solid #ddd;color:#777;font-size:16px;padding:0 1em}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body kbd,.popover kbd{background-color:#fcfcfc;border:1px solid;border-color:#ccc #ccc #bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb;color:#555;display:inline-block;font-size:11px;line-height:10px;padding:3px 5px;vertical-align:middle}.markdown-body .loweralpha{list-style-type:lower-alpha}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{font-weight:600;line-height:1.25;margin-bottom:16px;margin-top:24px}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{color:#000;vertical-align:middle;visibility:hidden}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{visibility:visible}.markdown-body h1 code,.markdown-body h1 tt,.markdown-body h2 code,.markdown-body h2 tt,.markdown-body h3 code,.markdown-body h3 tt,.markdown-body h4 code,.markdown-body h4 tt,.markdown-body h5 code,.markdown-body h5 tt,.markdown-body h6 code,.markdown-body h6 tt{font-size:inherit}.markdown-body h1{font-size:2em}.markdown-body h1,.markdown-body h2{border-bottom:1px solid #eee;padding-bottom:.3em}.markdown-body h2{font-size:1.5em}.markdown-body h3{font-size:1.25em}.markdown-body h4{font-size:1em}.markdown-body h5{font-size:.875em}.markdown-body h6{color:#777;font-size:.85em}.markdown-body ol,.markdown-body ul{padding-left:2em}.markdown-body ol.no-list,.markdown-body ul.no-list{list-style-type:none;padding:0}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-bottom:0;margin-top:0}.markdown-body li>p{margin-top:16px}.markdown-body li+li{padding-top:.25em}.markdown-body dl{padding:0}.markdown-body dl dt{font-size:1em;font-style:italic;font-weight:700;margin-top:16px;padding:0}.markdown-body dl dd{margin-bottom:16px;padding:0 16px}.markdown-body table{display:block;overflow:auto;width:100%;word-break:normal;word-break:keep-all}.markdown-body table th{font-weight:700}.markdown-body table td,.markdown-body table th{border:1px solid #ddd;padding:6px 13px}.markdown-body table tr{background-color:#fff;border-top:1px solid #ccc}.markdown-body table tr:nth-child(2n){background-color:#f8f8f8}.markdown-body img{background-color:#fff;box-sizing:initial;max-width:100%}.markdown-body img[align=right]{padding-left:20px}.markdown-body img[align=left]{padding-right:20px}.markdown-body .emoji{background-color:initial;max-width:none;vertical-align:text-top}.markdown-body span.frame{display:block;overflow:hidden}.markdown-body span.frame>span{border:1px solid #ddd;display:block;float:left;margin:13px 0 0;overflow:hidden;padding:7px;width:auto}.markdown-body span.frame span img{display:block;float:left}.markdown-body span.frame span span{clear:both;color:#333;display:block;padding:5px 0 0}.markdown-body span.align-center{clear:both;display:block;overflow:hidden}.markdown-body span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown-body span.align-center span img{margin:0 auto;text-align:center}.markdown-body span.align-right{clear:both;display:block;overflow:hidden}.markdown-body span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown-body span.align-right span img{margin:0;text-align:right}.markdown-body span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown-body span.float-left span{margin:13px 0 0}.markdown-body span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown-body span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown-body code,.markdown-body tt{background-color:#0000000a;border-radius:3px;font-size:85%;margin:0;padding:.2em 0}.markdown-body code:after,.markdown-body code:before,.markdown-body tt:after,.markdown-body tt:before{content:"\00a0";letter-spacing:-.2em}.markdown-body code br,.markdown-body tt br{display:none}.markdown-body del code{text-decoration:inherit}.markdown-body pre{word-wrap:normal}.markdown-body pre>code{background:#0000;border:0;font-size:100%;margin:0;padding:0;white-space:pre;word-break:normal}.markdown-body .highlight{margin-bottom:16px}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body .highlight pre,.markdown-body pre{background-color:#f7f7f7;border-radius:3px;font-size:85%;line-height:1.45;overflow:auto;padding:16px}.markdown-body pre code,.markdown-body pre tt{word-wrap:normal;background-color:initial;border:0;display:inline;line-height:inherit;margin:0;max-width:auto;overflow:visible;padding:0}.markdown-body pre code:after,.markdown-body pre code:before,.markdown-body pre tt:after,.markdown-body pre tt:before{content:normal}.markdown-body .csv-data td,.markdown-body .csv-data th{font-size:12px;line-height:1;overflow:hidden;padding:5px;text-align:left;white-space:nowrap}.markdown-body .csv-data .blob-line-num{background:#fff;border:0;padding:10px 8px 9px;text-align:right}.markdown-body .csv-data tr{border-top:0}.markdown-body .csv-data th{background:#f8f8f8;border-top:0;font-weight:700}.news .alert .markdown-body blockquote{border:0;padding:0 0 0 40px}.activity-tab .news .alert .commits,.activity-tab .news .markdown-body blockquote{padding-left:0}.task-list-item{list-style-type:none}.task-list-item label{font-weight:400}.task-list-item.enabled label{cursor:pointer}.task-list-item+.task-list-item{margin-top:3px}.task-list-item-checkbox{cursor:default!important;float:left;margin:.31em 0 .2em -1.3em!important;vertical-align:middle}.markdown-body{max-width:758px;overflow:visible!important;padding-bottom:40px;padding-top:40px;position:relative}.markdown-body .emoji{vertical-align:top}.markdown-body pre{border:inherit!important}.markdown-body code{color:inherit!important}.markdown-body pre code .wrapper{display:-moz-inline-flex;display:-ms-inline-flex;display:-o-inline-flex;display:inline-flex}.markdown-body pre code .gutter{float:left;overflow:hidden;-webkit-user-select:none;user-select:none}.markdown-body pre code .gutter.linenumber{border-right:3px solid #6ce26c!important;box-sizing:initial;color:#afafaf!important;cursor:default;display:inline-block;min-width:20px;padding:0 8px 0 0;position:relative;text-align:right;z-index:4}.markdown-body pre code .gutter.linenumber>span:before{content:attr(data-linenumber)}.markdown-body pre code .code{float:left;margin:0 0 0 16px}.markdown-body .gist .line-numbers{border-bottom:none;border-left:none;border-top:none}.markdown-body .gist .line-data{border:none}.markdown-body .gist table{border-collapse:inherit!important;border-spacing:0}.markdown-body code[data-gist-id]{background:none;padding:0}.markdown-body code[data-gist-id]:after,.markdown-body code[data-gist-id]:before{content:""}.markdown-body code[data-gist-id] .blob-num{border:unset}.markdown-body code[data-gist-id] table{margin-bottom:unset;overflow:unset}.markdown-body code[data-gist-id] table tr{background:unset}.markdown-body[dir=rtl] pre{direction:ltr}.markdown-body[dir=rtl] code{direction:ltr;unicode-bidi:embed}.markdown-body .alert>p:last-child{margin-bottom:0}.markdown-body pre.abc,.markdown-body pre.flow-chart,.markdown-body pre.graphviz,.markdown-body pre.mermaid,.markdown-body pre.sequence-diagram,.markdown-body pre.vega{background-color:inherit;border-radius:0;overflow:visible;text-align:center;white-space:inherit}.markdown-body pre.abc>code,.markdown-body pre.flow-chart>code,.markdown-body pre.graphviz>code,.markdown-body pre.mermaid>code,.markdown-body pre.sequence-diagram>code,.markdown-body pre.vega>code{text-align:left}.markdown-body pre.abc>svg,.markdown-body pre.flow-chart>svg,.markdown-body pre.graphviz>svg,.markdown-body pre.mermaid>svg,.markdown-body pre.sequence-diagram>svg,.markdown-body pre.vega>svg{height:100%;max-width:100%}.markdown-body pre>code.wrap{word-wrap:break-word;white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap}.markdown-body .alert>p:last-child,.markdown-body .alert>ul:last-child{margin-bottom:0}.markdown-body summary{display:list-item}.markdown-body summary:focus{outline:none}.markdown-body details summary{cursor:pointer}.markdown-body details:not([open])>:not(summary){display:none}.markdown-body figure{margin:1em 40px}.markdown-body .mark,.markdown-body mark{background-color:#fff1a7}.vimeo,.youtube{background-color:#000;background-position:50%;background-repeat:no-repeat;background-size:contain;cursor:pointer;display:table;overflow:hidden;text-align:center}.vimeo,.youtube{position:relative;width:100%}.youtube{padding-bottom:56.25%}.vimeo img{object-fit:contain;width:100%;z-index:0}.youtube img{object-fit:cover;z-index:0}.vimeo iframe,.youtube iframe,.youtube img{height:100%;left:0;position:absolute;top:0;width:100%}.vimeo iframe,.youtube iframe{vertical-align:middle;z-index:1}.vimeo .icon,.youtube .icon{color:#fff;height:auto;left:50%;opacity:.3;position:absolute;top:50%;transform:translate(-50%,-50%);transition:opacity .2s;width:auto;z-index:0}.vimeo:hover .icon,.youtube:hover .icon{opacity:.6;transition:opacity .2s}.slideshare .inner,.speakerdeck .inner{position:relative;width:100%}.slideshare .inner iframe,.speakerdeck .inner iframe{bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%}.figma{display:table;padding-bottom:56.25%;position:relative;width:100%}.figma iframe{border:1px solid #eee;bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%}.markmap-container{height:300px}.markmap-container>svg{height:100%;width:100%}.MJX_Assistive_MathML{display:none}#MathJax_Message{z-index:1000!important}.ui-infobar{color:#777;margin:25px auto -25px;max-width:760px;position:relative;z-index:2}.toc .invisable-node{list-style-type:none}.ui-toc{bottom:20px;position:fixed;z-index:998}.ui-toc.both-mode{margin-left:8px}.ui-toc.both-mode .ui-toc-label{border-bottom-left-radius:0;border-top-left-radius:0;height:40px;padding:10px 4px}.ui-toc-label{background-color:#e6e6e6;border:none;color:#868686;transition:opacity .2s}.ui-toc .open .ui-toc-label{color:#fff;opacity:1;transition:opacity .2s}.ui-toc-label:focus{background-color:#ccc;color:#000;opacity:.3}.ui-toc-label:hover{background-color:#ccc;opacity:1;transition:opacity .2s}.ui-toc-dropdown{margin-bottom:20px;margin-top:20px;max-height:70vh;max-width:45vw;overflow:auto;padding-left:10px;padding-right:10px;text-align:inherit;width:25vw}.ui-toc-dropdown>.toc{max-height:calc(70vh - 100px);overflow:auto}.ui-toc-dropdown[dir=rtl] .nav{letter-spacing:.0029em;padding-right:0}.ui-toc-dropdown a{overflow:hidden;text-overflow:ellipsis;white-space:pre}.ui-toc-dropdown .nav>li>a{color:#767676;display:block;font-size:13px;font-weight:500;padding:4px 20px}.ui-toc-dropdown .nav>li:first-child:last-child>ul,.ui-toc-dropdown .toc.expand ul{display:block}.ui-toc-dropdown .nav>li>a:focus,.ui-toc-dropdown .nav>li>a:hover{background-color:initial;border-left:1px solid #000;color:#000;padding-left:19px;text-decoration:none}.ui-toc-dropdown[dir=rtl] .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav>li>a:hover{border-left:none;border-right:1px solid #000;padding-right:19px}.ui-toc-dropdown .nav>.active:focus>a,.ui-toc-dropdown .nav>.active:hover>a,.ui-toc-dropdown .nav>.active>a{background-color:initial;border-left:2px solid #000;color:#000;font-weight:700;padding-left:18px}.ui-toc-dropdown[dir=rtl] .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav>.active>a{border-left:none;border-right:2px solid #000;padding-right:18px}.ui-toc-dropdown .nav .nav{display:none;padding-bottom:10px}.ui-toc-dropdown .nav>.active>ul{display:block}.ui-toc-dropdown .nav .nav>li>a{font-size:12px;font-weight:400;padding-bottom:1px;padding-left:30px;padding-top:1px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a{padding-right:30px}.ui-toc-dropdown .nav .nav>li>ul>li>a{font-size:12px;font-weight:400;padding-bottom:1px;padding-left:40px;padding-top:1px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a{padding-right:40px}.ui-toc-dropdown .nav .nav>li>a:focus,.ui-toc-dropdown .nav .nav>li>a:hover{padding-left:29px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:hover{padding-right:29px}.ui-toc-dropdown .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown .nav .nav>li>ul>li>a:hover{padding-left:39px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:hover{padding-right:39px}.ui-toc-dropdown .nav .nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>a{font-weight:500;padding-left:28px}.ui-toc-dropdown[dir=rtl] .nav .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>a{padding-right:28px}.ui-toc-dropdown .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active>a{font-weight:500;padding-left:38px}.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active>a{padding-right:38px}.markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang^=ja] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,ＭＳ ゴシック,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang=zh-tw] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang=zh-cn] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html .markdown-body[lang^=ja]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,ＭＳ ゴシック,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html .markdown-body[lang=zh-tw]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html .markdown-body[lang=zh-cn]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang^=ja] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Meiryo UI,MS PGothic,ＭＳ Ｐゴシック,sans-serif}html[lang=zh-tw] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Microsoft JhengHei UI,微軟正黑UI,sans-serif}html[lang=zh-cn] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Microsoft YaHei UI,微软雅黑UI,sans-serif}html .ui-toc-dropdown[lang^=ja]{font-family:Source Sans Pro,Helvetica,Arial,Meiryo UI,MS PGothic,ＭＳ Ｐゴシック,sans-serif}html .ui-toc-dropdown[lang=zh-tw]{font-family:Source Sans Pro,Helvetica,Arial,Microsoft JhengHei UI,微軟正黑UI,sans-serif}html .ui-toc-dropdown[lang=zh-cn]{font-family:Source Sans Pro,Helvetica,Arial,Microsoft YaHei UI,微软雅黑UI,sans-serif}.ui-affix-toc{max-height:70vh;max-width:15vw;overflow:auto;position:fixed;top:0}.back-to-top,.expand-toggle,.go-to-bottom{color:#999;display:block;font-size:12px;font-weight:500;margin-left:10px;margin-top:10px;padding:4px 10px}.back-to-top:focus,.back-to-top:hover,.expand-toggle:focus,.expand-toggle:hover,.go-to-bottom:focus,.go-to-bottom:hover{color:#563d7c;text-decoration:none}.back-to-top,.go-to-bottom{margin-top:0}.ui-user-icon{background-position:50%;background-repeat:no-repeat;background-size:cover;border-radius:50%;display:block;height:20px;margin-bottom:2px;margin-right:5px;margin-top:2px;width:20px}.ui-user-icon.small{display:inline-block;height:18px;margin:0 0 .2em;vertical-align:middle;width:18px}.ui-infobar>small>span{line-height:22px}.ui-infobar>small .dropdown{display:inline-block}.ui-infobar>small .dropdown a:focus,.ui-infobar>small .dropdown a:hover{text-decoration:none}.ui-more-info{color:#888;cursor:pointer;vertical-align:middle}.ui-more-info .fa{font-size:16px}.ui-connectedGithub,.ui-published-note{color:#888}.ui-connectedGithub{line-height:23px;white-space:nowrap}.ui-connectedGithub a.file-path{color:#888;padding-left:22px;text-decoration:none}.ui-connectedGithub a.file-path:active,.ui-connectedGithub a.file-path:hover{color:#888;text-decoration:underline}.ui-connectedGithub .fa{font-size:20px}.ui-published-note .fa{font-size:20px;vertical-align:top}.unselectable{-webkit-user-select:none;-o-user-select:none;user-select:none}.selectable{-webkit-user-select:text;-o-user-select:text;user-select:text}.inline-spoiler-section{cursor:pointer}.inline-spoiler-section .spoiler-text{background-color:#333;border-radius:2px}.inline-spoiler-section .spoiler-text>*{opacity:0}.inline-spoiler-section .spoiler-img{filter:blur(10px)}.inline-spoiler-section.raw{background-color:#333;border-radius:2px}.inline-spoiler-section.raw>*{opacity:0}.inline-spoiler-section.unveil{cursor:auto}.inline-spoiler-section.unveil .spoiler-text{background-color:#3333331a}.inline-spoiler-section.unveil .spoiler-text>*{opacity:1}.inline-spoiler-section.unveil .spoiler-img{filter:none}@media print{blockquote,div,img,pre,table{page-break-inside:avoid!important}a[href]:after{font-size:12px!important}}.markdown-body.slides{color:#222;position:relative;z-index:1}.markdown-body.slides:before{background-color:currentColor;bottom:0;box-shadow:0 0 0 50vw;content:"";display:block;left:0;position:absolute;right:0;top:0;z-index:-1}.markdown-body.slides section[data-markdown]{background-color:#fff;margin-bottom:1.5em;position:relative;text-align:center}.markdown-body.slides section[data-markdown] code{text-align:left}.markdown-body.slides section[data-markdown]:before{content:"";display:block;padding-bottom:56.23%}.markdown-body.slides section[data-markdown]>div:first-child{left:1em;max-height:100%;overflow:hidden;position:absolute;right:1em;top:50%;transform:translateY(-50%)}.markdown-body.slides section[data-markdown]>ul{display:inline-block}.markdown-body.slides>section>section+section:after{border:3px solid #777;content:"";height:1.5em;position:absolute;right:1em;top:-1.5em}.site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,sans-serif}html[lang^=ja] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,ＭＳ ゴシック,sans-serif}html[lang=zh-tw] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}body{font-smoothing:subpixel-antialiased!important;-webkit-font-smoothing:subpixel-antialiased!important;-moz-osx-font-smoothing:auto!important;-webkit-overflow-scrolling:touch;font-family:Source Sans Pro,Helvetica,Arial,sans-serif;letter-spacing:.025em}html[lang^=ja] body{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,ＭＳ ゴシック,sans-serif}html[lang=zh-tw] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}abbr[data-original-title],abbr[title]{cursor:help}body.modal-open{overflow-y:auto;padding-right:0!important}svg{text-shadow:none}
    </style>
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
    	<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js" integrity="sha256-3Jy/GbSLrg0o9y5Z5n1uw0qxZECH7C6OQpVBgNFYa0g=" crossorigin="anonymous"></script>
    	<script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js" integrity="sha256-g6iAfvZp+nDQ2TdTR/VVKJf3bGro4ub5fvWSWVRi2NE=" crossorigin="anonymous"></script>
		<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-shim.min.js" integrity="sha256-8E4Is26QH0bD52WoQpcB+R/tcWQtpzlCojrybUd7Mxo=" crossorigin="anonymous"></script>
    <![endif]-->
</head>

<body>
    <div id="doc" class="markdown-body container-fluid comment-enabled comment-inner" data-hard-breaks="true"><p><strong><span>Document number:</span></strong><span> P2643R0</span><br>
<strong><span>Date</span></strong><span>: 2022-09-15</span><br>
<strong><span>Reply to</span></strong><span>: Gonzalo Brito Gadeschi &lt;gonzalob _at_ </span><a href="http://nvidia.com" target="_blank" rel="noopener"><span>nvidia.com</span></a><span>&gt;</span><br>
<strong><span>Authors:</span></strong><span> Gonzalo Brito Gadeschi, Olivier Giroux, Thomas Rodgers</span><br>
<strong><span>Audience:</span></strong><span> Concurrency</span></p><style>
ins {
    color:green; 
    background-color:yellow;
    text-decoration:underline;
}
del { 
    color:red;
    background-color:yellow;
    text-decoration:line-through;
}
    .markdown-body { 
    max-width: 900px; 
}
</style><h1 id="Improving-C-concurrency-features" data-id="Improving-C-concurrency-features"><a class="anchor hidden-xs" href="#Improving-C-concurrency-features" title="Improving-C-concurrency-features"><span class="octicon octicon-link"></span></a><span>Improving C++ concurrency features</span></h1><h2 id="Revisions" data-id="Revisions"><a class="anchor hidden-xs" href="#Revisions" title="Revisions"><span class="octicon octicon-link"></span></a><span>Revisions</span></h2><p><span>This is the initial revision.</span></p><h2 id="Introduction" data-id="Introduction"><a class="anchor hidden-xs" href="#Introduction" title="Introduction"><span class="octicon octicon-link"></span></a><span>Introduction</span></h2><p><span>When we applied P1135R6 to C++20, we introduced several new concurrency constructs to the C++ concurrency library:</span></p><ul>
<li><span>In </span><code>&lt;atomic&gt;</code><span>, the member functions </span><code>wait</code><span>, </span><code>notify_one</code><span> and </span><code>notify_all</code><span> were added to class template </span><code>atomic&lt;&gt;</code><span> and class </span><code>atomic_flag</code><span>, and free function versions of the same also.</span></li>
<li><span>In </span><code>&lt;semaphore&gt;</code><span>, the class template </span><code>counting_semaphore&lt;&gt;</code><span> and class </span><code>binary_semaphore</code><span> were introduced.</span></li>
<li><span>In </span><code>&lt;barrier&gt;</code><span> and </span><code>&lt;latch&gt;</code><span>, the class template </span><code>barrier&lt;&gt;</code><span> and class </span><code>latch</code><span> were introduced.</span></li>
</ul><p><span>Though each element included was long coming, and had much implementation experience behind it, fresh user feedback tells us that some improvements could still be made.</span></p><h2 id="Proposed-direction" data-id="Proposed-direction"><a class="anchor hidden-xs" href="#Proposed-direction" title="Proposed-direction"><span class="octicon octicon-link"></span></a><span>Proposed direction</span></h2><p><span>The following is a grossly priority-ordered list of requests that users and implementers both have voiced over the last year:</span></p><ol>
<li><span>Add timed versions of </span><code>atomic::wait</code><span>.</span></li>
</ol><blockquote>
<p><span>The primary purpose of this facility is to make it easier to implement other concurrency facilities, but often these other facilities expose timed waiting facilities themselves. Without timed versions of </span><code>wait</code><span>, the programmer is left to ad-hoc solutions for timed waiting facilities, and perhaps even all waiting facilities. Anecdotally, at least two implementations of C++20 have added internal timed versions of this facility to implement </span><code>&lt;semaphore&gt;</code><span>.</span></p>
<p><span>Adding timed versions of </span><code>atomic::wait</code><span> removes hurdles to adoption of this facility for its intended purpose.</span></p>
<p><span>Adding timed versions of </span><code>atomic::wait</code><span> will require a discussion of what facilities from </span><code>&lt;chrono&gt;</code><span> need to be present in </span><code>&lt;atomic&gt;</code><span> for freestanding implementations.</span></p>
</blockquote><ol start="2">
<li><span>Return the last observed value from </span><code>atomic::wait</code><span>.</span></li>
</ol><blockquote>
<p><span>After the return from </span><code>wait</code><span>, it is common for programs to reload the value of the atomic object. By necessity, the implementation of </span><code>wait</code><span> already loaded this value, to compare it with the operand supplied and return non-spuriously. This is duplicate work which, in principle, could be optimized away by the compiler but conservatively isn’t.</span></p>
<p><span>Returning the value from </span><code>atomic::wait</code><span> is a straightforward way to recover performance lost from the duplicate work.</span></p>
</blockquote><ol start="3">
<li>
<p><span>Avoid spurious polling in </span><code>atomic::wait</code><span> with </span><em><strong><span>at least one of</span></strong></em><span>:</span><br>
<span>a. Add an overload of </span><code>wait</code><span> taking a predicate instead of a value.</span></p>
<blockquote>
<p><span>When the program is waiting for a condition different from “not equal to”, there is an added re-try loop around the </span><code>wait</code><span> operation in the program. This loop causes </span><em><span>each</span></em><span> call to </span><code>wait</code><span> to be performed as if it were the </span><em><span>first</span></em><span> call to </span><code>wait</code><span>, oblivious to the fact that the program has already been waiting for some time. This leads to re-executing the short-term polling strategy.</span></p>
<p><span>Taking a predicate instead of a value allows us to push the program-defined condition inside of </span><code>atomic::wait</code><span>, delete the outer loop, and allows the implementation to track time spent.</span></p>
<p><span>At least two implementations currently implement </span><code>atomic::wait</code><span> in terms of a wait taking a predicate.</span></p>
</blockquote>
<p><span>b. Add a hint operand to </span><code>wait</code><span> to steer the internal strategy.</span></p>
<blockquote>
<p><span>By default, that short-term strategy inside of </span><code>wait</code><span> is to poll the atomic object’s value for some time, so as to avoid limiting the responsiveness of the program to that of the operating system kernel’s scheduler. Sometimes, however, it is known that either (a) an event cannot or is not hoped to occur in this short of a window of time, or (b) the program has already supplied its own polling strategy before the call to </span><code>wait</code><span>, or © this call to </span><code>wait</code><span> is not the first and should be considered a long-term wait.</span></p>
<p><span>Taking a hint would let the program indicate whether the short-term strategy of </span><code>atomic::wait</code><span> should execute or not.</span></p>
</blockquote>
</li>
<li>
<p><span>Add timed versions of </span><code>barrier::wait</code><span> and </span><code>latch::wait</code><span> also.</span></p>
</li>
</ol><blockquote>
<p><span>Since every waiting facility in the concurrency library has timed wait functions at this point, it makes sense to add timed versions of these as well.</span></p>
<p><span>Although this is a very weak reason to do anything, there is also no clear reason why we should not do it.</span></p>
</blockquote><h2 id="Design" data-id="Design"><a class="anchor hidden-xs" href="#Design" title="Design"><span class="octicon octicon-link"></span></a><span>Design</span></h2><p><span>The design of the features above is mostly orthogonal, and this section explores them independently.</span></p><ol>
<li><strong><span>Return last observed value from atomic </span><code>::wait</code><span> APIs</span></strong><span>: solved as </span><del><span>void</span></del><ins><span>T</span></ins><span> wait(…);</span></li>
<li><strong><span>Fallible and timed versions of wait APIs</span></strong><span>:</span>
<ul>
<li>
<p><span>Solved by adding:</span></p>
<ul>
<li><code>optional&lt;T&gt; try_wait(...)</code><span>,</span></li>
<li><code>optional&lt;T&gt; try_wait_for(..., chrono::duration&lt;Rep, Period&gt; const&amp;)</code><span>, and</span></li>
<li><code>optional&lt;T&gt; try_wait_until(..., chrono::time_point&lt;Clock, Duration&gt; const&amp;)</code></li>
</ul>
<p><span>methods that return </span><code>nullopt</code><span> if the wait operation did not synchronize, and an </span><code>optional&lt;T&gt;</code><span> containing the </span><code>T</code><span> value observed if it did synchronize.</span></p>
</li>
</ul>
</li>
</ol><h2 id="Wording" data-id="Wording"><a class="anchor hidden-xs" href="#Wording" title="Wording"><span class="octicon octicon-link"></span></a><span>Wording</span></h2><h3 id="Return-last-observed-value-from-atomicwait" data-id="Return-last-observed-value-from-atomicwait"><a class="anchor hidden-xs" href="#Return-last-observed-value-from-atomicwait" title="Return-last-observed-value-from-atomicwait"><span class="octicon octicon-link"></span></a><span>Return last observed value from </span><code>atomic::wait</code></h3><p><span>To </span><a href="http://eel.is/c++draft/atomics.ref.generic.general" target="_blank" rel="noopener"><span>[atomics.ref.generic.general]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic_ref {  // [atomics.ref.generic.general]
    <del>void</del><ins>T</ins> wait(T, memory_order = memory_order::seq_cst) const noexcept;
  };
}</code></pre><blockquote>
<p><ins><strong><span>UNRESOLVED QUESTION:</span></strong><span> all </span><code>atomic_ref</code><span> types are missing </span><code>volatile</code><span> wait overloads?</span></ins></p>
</blockquote><p><span>To </span><a href="http://eel.is/c++draft/atomics#lib:wait,atomic_ref%3cT%3e" target="_blank" rel="noopener"><span>[atomics.ref.ops]</span></a><span>:</span></p><pre><code><del>void</del><ins>T</ins> wait(T old, memory_order order = memory_order::seq_cst) const noexcept;</code></pre><ul>
<li><em><span>Preconditions</span></em><span>: </span><code>order</code><span> is neither </span><code>memory_order::release</code><span> nor </span><code>memory_order::acq_rel</code><span>.</span></li>
<li><em><span>Effects</span></em><span>: Repeatedly performs the following steps, in order:</span>
<ol>
<li><span>Evaluates </span><code>load(order)</code><span> and compares its value representation for equality against that of </span><code>old</code><span>.</span></li>
<li><span>If they compare unequal, returns</span><ins><span> the result of the evaluation of </span><code>load(order)</code><span> in the previous step</span></ins><span>.</span></li>
<li><span>Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously.</span></li>
</ol>
</li>
<li><em><span>Remarks</span></em><span>: This function is an atomic waiting operation (</span><a href="http://eel.is/c++draft/atomics#wait" target="_blank" rel="noopener"><span>atomics.wait</span></a><span>) on atomic object </span><code>*ptr</code><span>.</span></li>
</ul><p><span>To </span><a href="http://eel.is/c++draft/atomics.ref.int" target="_blank" rel="noopener"><span>[atomics.ref.int]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;&gt; struct atomic_ref&lt;integral&gt; {
    <del>void</del><ins>T</ins> wait(integral, memory_order = memory_order::seq_cst) const noexcept;
  };
}</code></pre><p><span>To </span><a href="http://eel.is/c++draft/atomics.ref.float" target="_blank" rel="noopener"><span>[atomics.ref.float]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;&gt; struct atomic_ref&lt;floating-point&gt; {
    <del>void</del><ins>T</ins> wait(floating-point, memory_order = memory_order::seq_cst) const noexcept;
  };
}</code></pre><p><span>To </span><a href="http://eel.is/c++draft/atomics.ref.pointer" target="_blank" rel="noopener"><span>[atomics.ref.pointer]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic_ref&lt;T*&gt; {
    <del>void</del><ins>T*</ins> wait(T*, memory_order = memory_order::seq_cst) const noexcept;
  };
}</code></pre><p><span>To </span><a href="http://eel.is/c++draft/atomics.types.generic.general" target="_blank" rel="noopener"><span>[atomics.types.generic.general]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic {
    <del>void</del><ins>T</ins> wait(T, memory_order = memory_order::seq_cst) const volatile noexcept;
    <del>void</del><ins>T</ins> wait(T, memory_order = memory_order::seq_cst) const noexcept;
  };
}</code></pre><p><span>To </span><a href="http://eel.is/c++draft/atomics.types.operations#lib:wait,atomic" target="_blank" rel="noopener"><span>[atomics.types.operations]</span></a><span>:</span></p><pre><code><del>void</del><ins>T</ins> wait(T old, memory_order order = memory_order::seq_cst) const volatile noexcept;
<del>void</del><ins>T</ins> wait(T old, memory_order order = memory_order::seq_cst) const noexcept;</code></pre><ul>
<li><em><span>Preconditions</span></em><span>: order is neither </span><code>memory_order::release</code><span> nor </span><code>memory_order::acq_rel</code><span>.</span></li>
<li><em><span>Effects</span></em><span>: Repeatedly performs the following steps, in order:</span>
<ol>
<li><span>Evaluates </span><code>load(order)</code><span> and compares its value representation for equality against that of </span><code>old</code><span>.</span></li>
<li><span>If they compare unequal, returns</span><ins><span> the result of the evaluation of </span><code>load(order)</code><span> in the previous step</span></ins><span>.</span></li>
<li><span>Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously.</span></li>
</ol>
</li>
<li><em><span>Remarks</span></em><span>: This function is an atomic waiting operation (</span><a href="http://eel.is/c++draft/atomics#wait" target="_blank" rel="noopener"><span>atomics.wait</span></a><span>).</span></li>
</ul><p><span>To </span><a href="http://eel.is/c++draft/atomics.types.int" target="_blank" rel="noopener"><span>[atomics.types.int]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;&gt; struct atomic&lt;integral&gt; {
    <del>void</del><ins>T</ins> wait(integral, memory_order = memory_order::seq_cst) const volatile noexcept;
    <del>void</del><ins>T</ins> wait(integral, memory_order = memory_order::seq_cst) const noexcept;
  };
}</code></pre><p><span>To </span><a href="http://eel.is/c++draft/atomics.types.float" target="_blank" rel="noopener"><span>[atomics.types.float]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;&gt; struct atomic&lt;floating-point&gt; {
    <del>void</del><ins>T</ins> wait(floating-point, memory_order = memory_order::seq_cst) const volatile noexcept;
    <del>void</del><ins>T</ins> wait(floating-point, memory_order = memory_order::seq_cst) const noexcept;
  };
}</code></pre><p><span>To </span><a href="http://eel.is/c++draft/atomics.types.pointer" target="_blank" rel="noopener"><span>[atomics.types.pointer]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic&lt;T*&gt; {
    <del>void</del><ins>T*</ins> wait(T*, memory_order = memory_order::seq_cst) const volatile noexcept;
    <del>void</del><ins>T*</ins> wait(T*, memory_order = memory_order::seq_cst) const noexcept;
  };
}</code></pre><p><span>To </span><a href="http://eel.is/c++draft/util.smartptr.atomic.shared" target="_blank" rel="noopener"><span>[util.smartptr.atomic.shared]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic&lt;shared_ptr&lt;T&gt;&gt; {
    <del>void</del><ins>shared_ptr&lt;T&gt;</ins> wait(shared_ptr&lt;T&gt; old, memory_order = memory_order::seq_cst) const noexcept;
  };
}</code></pre><p><span>and</span></p><pre><code><del>void</del><ins>shared_ptr&lt;T&gt;</ins> wait(shared_ptr&lt;T&gt; old, memory_order order = memory_order::seq_cst) const noexcept;</code></pre><ul>
<li><em><span>Preconditions</span></em><span>: </span><code>order</code><span> is neither </span><code>memory_order::release</code><span> nor </span><code>memory_order::acq_rel</code><span>.</span></li>
<li><em><span>Effects</span></em><span>: Repeatedly performs the following steps, in order:</span>
<ol>
<li><span>Evaluates </span><code>load(order)</code><span> and compares it to </span><code>old</code><span>.</span></li>
<li><span>If the two are not equivalent, returns</span><ins><span> the result of the evaluation of </span><code>load(order)</code><span> in the previous step</span></ins><span>.</span></li>
<li><span>Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously.</span></li>
</ol>
</li>
<li><em><span>Remarks</span></em><span>: Two </span><code>shared_ptr</code><span> objects are equivalent if they store the same pointer and either share ownership or are both empty. This function is an atomic waiting operation (</span><a href="http://eel.is/c++draft/atomics.wait" target="_blank" rel="noopener"><span>atomics.wait</span></a><span>).</span></li>
</ul><p><span>To </span><a href="http://eel.is/c++draft/util.smartptr.atomic.weak" target="_blank" rel="noopener"><span>[util.smartptr.atomic.weak]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic&lt;weak_ptr&lt;T&gt;&gt; {
    <del>void</del><ins>weak_ptr&lt;T&gt;</ins> wait(weak_ptr&lt;T&gt; old, memory_order = memory_order::seq_cst) const noexcept;
  };
}</code></pre><pre><code><del>void</del><ins>weak_ptr&lt;T&gt;</ins> wait(weak_ptr&lt;T&gt; old, memory_order order = memory_order::seq_cst) const noexcept;</code></pre><ul>
<li><em><span>Preconditions</span></em><span>: order is neither </span><code>memory_order::release</code><span> nor </span><code>memory_order::acq_rel</code><span>.</span></li>
<li><em><span>Effects</span></em><span>: Repeatedly performs the following steps, in order:</span>
<ol>
<li><span>Evaluates </span><code>load(order)</code><span> and compares it to </span><code>old</code><span>.</span></li>
<li><span>If the two are not equivalent, returns</span><ins><span> the result of the evaluation of </span><code>load(order)</code><span> in the previous step</span></ins><span>.</span></li>
<li><span>Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously.</span></li>
</ol>
</li>
<li><em><span>Remarks</span></em><span>: Two </span><code>weak_ptr</code><span> objects are equivalent if they store the same pointer and either share ownership or are both empty. This function is an atomic waiting operation (</span><a href="http://eel.is/c++draft/atomics#wait" target="_blank" rel="noopener"><span>atomics.wait</span></a><span>).</span></li>
</ul><p><span>No changes to </span><a href="http://eel.is/c++draft/atomics.nonmembers" target="_blank" rel="noopener"><span>[atomics.nonmembers]</span></a><span> are needed.</span></p><p><span>No changes to </span><a href="http://eel.is/c++draft/atomics.flag" target="_blank" rel="noopener"><span>[atomic.flag]</span></a><span>'s </span><code>wait</code><span> APIs are needed.</span></p><h3 id="Fallible-and-timed-versions-of-wait-APIs" data-id="Fallible-and-timed-versions-of-wait-APIs"><a class="anchor hidden-xs" href="#Fallible-and-timed-versions-of-wait-APIs" title="Fallible-and-timed-versions-of-wait-APIs"><span class="octicon octicon-link"></span></a><span>Fallible and timed-versions of </span><code>::wait</code><span> APIs</span></h3><p><span>To </span><a href="http://eel.is/c++draft/atomics.ref.generic.general" target="_blank" rel="noopener"><span>[atomics.ref.generic.general]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic_ref {  // [atomics.ref.generic.general]
    <ins>
    optional&lt;T&gt; try_wait(T, memory_order = memory_order::seq_cst) const noexcept;
    template &lt;class Rep, class Period&gt;
    optional&lt;T&gt; try_wait_for(
      T, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;
    template &lt;class Clock, class Duration&gt;
    optional&lt;T&gt; try_wait_until(
      T, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;</ins>
  };
}</code></pre><blockquote>
<p><ins><strong><span>UNRESOLVED QUESTION:</span></strong><span> all </span><code>atomic_ref</code><span> types are missing </span><code>volatile</code><span> wait overloads?</span></ins></p>
</blockquote><p><span>To </span><a href="http://eel.is/c++draft/atomics#lib:wait,atomic_ref%3cT%3e" target="_blank" rel="noopener"><span>[atomics.ref.ops]</span></a><span>:</span></p><pre><code><ins>optional&lt;T&gt; try_wait(T old, memory_order order = memory_order::seq_cst) const noexcept;</ins></code></pre><ul>
<li><ins><em><span>Preconditions</span></em><span>: </span><code>order</code><span> is neither </span><code>memory_order::release</code><span> nor </span><code>memory_order::acq_rel</code><span>.</span></ins></li>
<li><ins><em><span>Effects</span></em><span>: Performs the following steps in order:</span></ins>
<ol>
<li><ins><span>Evaluates </span><code>load(order)</code><span> and compares its value representation for equality against that of </span><code>old</code><span>.</span></ins></li>
<li><ins><span>If they compare unequal, returns the result of the evaluation of </span><code>load(order)</code><span> in the previous step</span></ins><span>.</span></li>
<li><ins><span>Otherwise, there is no effect and it returns </span><code>nullopt</code><span>.</span><br></ins><br>
<ins><em><span>Remarks</span></em><span>: This function is an atomic waiting operation (</span><a href="http://eel.is/c++draft/atomics.wait" target="_blank" rel="noopener"><span>atomics.wait</span></a><span>).</span></ins></li>
</ol>
</li>
</ul><pre><code><ins>template &lt;class Rep, class Period&gt;
optional&lt;T&gt; try_wait_for(T old, 
    chrono::duration&lt;Rep, Period&gt; const&amp; rel_time,
    memory_order order = memory_order::seq_cst
) const noexcept;
template &lt;class Clock, class Duration&gt;
optional&lt;T&gt; try_wait_until(T old, 
    chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time,
    memory_order order = memory_order::seq_cst
) const noexcept;</ins></code></pre><ul>
<li><ins><em><span>Preconditions</span></em><span>: </span><code>order</code><span> is neither </span><code>memory_order::release</code><span> nor </span><code>memory_order::acq_rel</code><span>.</span></ins></li>
<li><ins><em><span>Effects</span></em><span>: Repeatedly performs the following steps, in order:</span></ins>
<ol>
<li><ins><span>Evaluates </span><code>load(order)</code><span> and compares its value representation for equality against that of </span><code>old</code><span>.</span></ins></li>
<li><ins><span>If they compare unequal, returns the result of the evaluation of </span><code>load(order)</code><span> in the previous step</span></ins><span>.</span></li>
<li><ins><span>Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously or the timeout expired. If it is unblocked by the timeout there is no effect and it returns </span><code>nullopt</code><span>.</span><br></ins><br>
<ins><span>The timeout expires (</span><a href="http://eel.is/c++draft/thread.req.timing" target="_blank" rel="noopener"><span>thread.req.timing</span></a><span>) when the current time is after </span><code>abs_time</code><span> (for </span><code>try_wait_until</code><span>) or when at least </span><code>rel_time</code><span> has passed from the start of the function (for </span><code>try_wait_for</code><span>).</span><br></ins><br>
<ins><span>An implementation should ensure that </span><code>try_wait_for</code><span> and </span><code>try_wait_until</code><span> do not consistently return </span><code>nullopt</code><span> in the absence of contending atomic operations.</span></ins></li>
</ol>
</li>
<li><ins><em><span>Throws</span></em><span>: Timeout-related exceptions (</span><a href="http://eel.is/c++draft/thread.req.timing" target="_blank" rel="noopener"><span>thread.req.timing</span></a><span>).</span></ins></li>
<li><ins><em><span>Remarks</span></em><span>: This function is an atomic waiting operation (</span><a href="http://eel.is/c++draft/atomics#wait" target="_blank" rel="noopener"><span>atomics.wait</span></a><span>) on atomic object </span><code>*ptr</code></ins><span>.</span></li>
</ul><p><span>To </span><a href="http://eel.is/c++draft/atomics.ref.int" target="_blank" rel="noopener"><span>[atomics.ref.int]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;&gt; struct atomic_ref&lt;integral&gt; {
    <ins>optional&lt;integral&gt; try_wait(integral, memory_order = memory_order::seq_cst) const noexcept;
    template &lt;class Rep, class Period&gt;
    optional&lt;integral&gt; try_wait_for(
      integral, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;
    template &lt;class Clock, class Duration&gt;
    optional&lt;integral&gt; try_wait_until(
      integral, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;</ins>
  };
}</code></pre><p><span>To </span><a href="http://eel.is/c++draft/atomics.ref.float" target="_blank" rel="noopener"><span>[atomics.ref.float]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;&gt; struct atomic_ref&lt;floating-point&gt; {
    <ins>optional&lt;floating-point&gt; try_wait(floating-point, memory_order = memory_order::seq_cst) const noexcept;
    template &lt;class Rep, class Period&gt;
    optional&lt;floating-point&gt; try_wait_for(
      floating-point, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;
    template &lt;class Clock, class Duration&gt;
    optional&lt;floating-point&gt; try_wait_until(
      floating-point, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;</ins>
  };
}</code></pre><p><span>To </span><a href="http://eel.is/c++draft/atomics.ref.pointer" target="_blank" rel="noopener"><span>[atomics.ref.pointer]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic_ref&lt;T*&gt; {
    <ins>optional&lt;T*&gt; try_wait(T*, memory_order = memory_order::seq_cst) const noexcept;
    template &lt;class Rep, class Period&gt;
    optional&lt;T*&gt; try_wait_for(
      T*, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;
    template &lt;class Clock, class Duration&gt;
    optional&lt;T*&gt; try_wait_until(
      T*, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;</ins>
  };
}</code></pre><p><span>To </span><a href="http://eel.is/c++draft/atomics.types.generic.general" target="_blank" rel="noopener"><span>[atomics.types.generic.general]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic {
    <ins>optional&lt;T&gt; try_wait(T, memory_order = memory_order::seq_cst) const noexcept;
    optional&lt;T&gt; try_wait(T, memory_order = memory_order::seq_cst) const volatile noexcept;
    template &lt;class Rep, class Period&gt;
    optional&lt;T&gt; try_wait_for(
      integral, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;
     optional&lt;T&gt; try_wait_for(
      integral, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
     ) const volatile noexcept;
    template &lt;class Clock, class Duration&gt;
    optional&lt;T&gt; try_wait_until(
      integral, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;
    template &lt;class Clock, class Duration&gt;
    optional&lt;T&gt; try_wait_until(
      integral, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const volatile noexcept;
     </ins>
  };
}</code></pre><p><span>To </span><a href="http://eel.is/c++draft/atomics.types.operations#lib:wait,atomic" target="_blank" rel="noopener"><span>[atomics.types.operations]</span></a><span>:</span></p><pre><code><ins>optional&lt;T&gt; try_wait(T, memory_order = memory_order::seq_cst) const noexcept;
optional&lt;T&gt; try_wait(T, memory_order = memory_order::seq_cst) const volatile noexcept;
template &lt;class Rep, class Period&gt;
optional&lt;T&gt; try_wait_for(T old, 
                         chrono::duration&lt;Rep, Period&gt; const&amp; rel_time,
                         memory_order order = memory_order::seq_cst
                        ) const noexcept;
template &lt;class Rep, class Period&gt;
optional&lt;T&gt; try_wait_for(T old, 
                         chrono::duration&lt;Rep, Period&gt; const&amp; rel_time,
                         memory_order order = memory_order::seq_cst
                        ) const volatile noexcept;
template &lt;class Clock, class Duration&gt;
optional&lt;T&gt; try_wait_until(T old, 
                           chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time,
                           memory_order order = memory_order::seq_cst
                          ) const noexcept;
template &lt;class Clock, class Duration&gt;
optional&lt;T&gt; try_wait_until(T old, 
                           chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time,
                           memory_order order = memory_order::seq_cst
                          ) const volatile noexcept;</ins></code></pre><blockquote>
<p><ins><strong><span>EDITORIAL</span></strong><span>: analogous to </span><code>atomic_ref</code><span>. Intentionally left out from the current revision of this paper.</span></ins></p>
</blockquote><p><span>To </span><a href="http://eel.is/c++draft/atomics.types.int" target="_blank" rel="noopener"><span>[atomics.types.int]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;&gt; struct atomic&lt;integral&gt; {
    <ins>optional&lt;integral&gt; try_wait(integral, memory_order = memory_order::seq_cst) const noexcept;
    optional&lt;integral&gt; try_wait(integral, memory_order = memory_order::seq_cst) const volatile noexcept;
    template &lt;class Rep, class Period&gt;
    optional&lt;integral&gt; try_wait_for(
      integral, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;
    template &lt;class Rep, class Period&gt;
    optional&lt;integral&gt; try_wait_for(
      integral, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
     ) const volatile noexcept;
    template &lt;class Clock, class Duration&gt;
    optional&lt;integral&gt; try_wait_until(
      integral, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;
    template &lt;class Clock, class Duration&gt;
    optional&lt;integral&gt; try_wait_until(
      integral, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const volatile noexcept;</ins>
  };
}</code></pre><p><span>To </span><a href="http://eel.is/c++draft/atomics.types.float" target="_blank" rel="noopener"><span>[atomics.types.float]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;&gt; struct atomic&lt;floating-point&gt; {
    <ins>optional&lt;floating-point&gt; try_wait(floating-point, memory_order = memory_order::seq_cst) const noexcept;
    optional&lt;floating-point&gt; try_wait(floating-point, memory_order = memory_order::seq_cst) const volatile noexcept;
    template &lt;class Rep, class Period&gt;
    optional&lt;floating-point&gt; try_wait_for(
      floating-point, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;
    template &lt;class Rep, class Period&gt;
    optional&lt;floating-point&gt; try_wait_for(
      floating-point, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
     ) const volatile noexcept;
    template &lt;class Clock, class Duration&gt;
    optional&lt;floating-point&gt; try_wait_until(
      floating-point, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;
    template &lt;class Clock, class Duration&gt;
    optional&lt;floating-point&gt; try_wait_until(
      floating-point, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const volatile noexcept;</ins>
  };
}</code></pre><p><span>To </span><a href="http://eel.is/c++draft/atomics.types.pointer" target="_blank" rel="noopener"><span>[atomics.types.pointer]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic&lt;T*&gt; {
    <ins>optional&lt;T*&gt; try_wait(T*, memory_order = memory_order::seq_cst) const noexcept;
    optional&lt;T*&gt; try_wait(T*, memory_order = memory_order::seq_cst) const volatile noexcept;
    template &lt;class Rep, class Period&gt;
    optional&lt;T*&gt; try_wait_for(
      T*, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;
    template &lt;class Rep, class Period&gt;
    optional&lt;T*&gt; try_wait_for(
      T*, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
     ) const volatile noexcept;
    template &lt;class Clock, class Duration&gt;
    optional&lt;T*&gt; try_wait_until(
      T*, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;
    template &lt;class Clock, class Duration&gt;
    optional&lt;T*&gt; try_wait_until(
      T*, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const volatile noexcept;</ins>
  };
}</code></pre><p><span>To </span><a href="http://eel.is/c++draft/util.smartptr.atomic.shared" target="_blank" rel="noopener"><span>[util.smartptr.atomic.shared]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic&lt;shared_ptr&lt;T&gt;&gt; {
    <ins>optional&lt;shared_ptr&lt;T&gt;&gt; try_wait(shared_ptr&lt;T&gt;, memory_order = memory_order::seq_cst) const noexcept;
    template &lt;class Rep, class Period&gt;
    optional&lt;shared_ptr&lt;T&gt;&gt; try_wait_for(
      shared_ptr&lt;T&gt;l, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;
    template &lt;class Clock, class Duration&gt;
    optional&lt;shared_ptr&lt;T&gt;&gt; try_wait_until(
      shared_ptr&lt;T&gt;, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;</ins>
  };
}</code></pre><blockquote>
<p><ins><strong><span>EDITORIAL</span></strong><span>: analogous to the </span><code>try_wait</code><span> APIS of </span><code>atomic_ref</code><span>, with </span><code>shared_ptr</code><span>/</span><code>weak_ptr</code><span> tweaks. Intentionally left out of the current revision of this paper.</span></ins></p>
</blockquote><p><span>To </span><a href="http://eel.is/c++draft/util.smartptr.atomic.weak" target="_blank" rel="noopener"><span>[util.smartptr.atomic.weak]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic&lt;weak_ptr&lt;T&gt;&gt; {
    <ins>optional&lt;weak_ptr&lt;T&gt;&gt; try_wait(weak_ptr&lt;T&gt;, memory_order = memory_order::seq_cst) const noexcept;
    template &lt;class Rep, class Period&gt;
    optional&lt;weak_ptr&lt;T&gt;&gt; try_wait_for(
      weak_ptr&lt;T&gt;l, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;
    template &lt;class Clock, class Duration&gt;
    optional&lt;weak_ptr&lt;T&gt;&gt; try_wait_until(
      weak_ptr&lt;T&gt;, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;</ins>
  };
}</code></pre><blockquote>
<p><ins><strong><span>EDITORIAL</span></strong><span>: analogous to the </span><code>try_wait</code><span> APIS of </span><code>atomic_ref</code><span>, with </span><code>shared_ptr</code><span>/</span><code>weak_ptr</code><span> tweaks. Intentionally left out of the current revision of this paper.</span></ins></p>
</blockquote><blockquote>
<p><ins><strong><span>EDITORIAL</span></strong><span>: No changes to </span><a href="http://eel.is/c++draft/atomics.nonmembers" target="_blank" rel="noopener"><span>[atomics.nonmembers]</span></a><span> are needed.</span></ins></p>
</blockquote><p><span>To </span><a href="http://eel.is/c++draft/atomics.flag" target="_blank" rel="noopener"><span>[atomic.flag]</span></a><span>:</span></p><pre><code>namespace std {
  struct atomic_flag {
    <ins>bool try_wait(bool, memory_order = memory_order::seq_cst) const noexcept;
    bool try_wait(bool, memory_order = memory_order::seq_cst) const volatile noexcept;
    template &lt;class Rep, class Period&gt;
    bool try_wait_for(
      bool, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
    ) const noexcept;
    template &lt;class Rep, class Period&gt;
    bool try_wait_for(
      bool, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, 
      memory_order = memory_order::seq_cst
    ) const volatile noexcept;
    template &lt;class Clock, class Duration&gt;
    bool try_wait_until(
      bool, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const noexcept;
     template &lt;class Clock, class Duration&gt;
     bool try_wait_until(
      bool, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, 
      memory_order = memory_order::seq_cst
     ) const volatile noexcept;</ins>
  };
}</code></pre><pre><code><ins>bool atomic_flag_try_wait(const atomic_flag* object, bool old) noexcept;
bool atomic_flag_try_wait(const volatile atomic_flag* object, bool old) noexcept;
bool atomic_flag_try_wait_explicit(const atomic_flag* object, bool old, memory_order order = memory_order::seq_cst) noexcept;
bool atomic_flag_try_wait_explicit(const volatile atomic_flag* object, bool old, memory_order order = memory_order::seq_cst) noexcept;
bool atomic_flag::try_wait(bool old, memory_order order = memory_order::seq_cst) const noexcept;
bool atomic_flag::try_wait(bool old, memory_order order = memory_order::seq_cst) const volatile noexcept;</ins></code></pre><p><ins><span>For </span><code>atomic_flag_try_wait</code><span>, let </span><code>order</code><span> be </span><code>memory_order::seq_cst</code><span>. Let </span><code>flag</code><span> be </span><code>object</code><span> for the non-member functions, and </span><code>this</code><span> for the member functions.</span></ins></p><ul>
<li><ins><span>Preconditions_: </span><code>order</code><span> is neither </span><code>memory_order::release</code><span> nor </span><code>memory_order::acq_rel</code><span>.</span></ins></li>
<li><ins><em><span>Effects</span></em><span>: Repeatedly performs the following steps, in order:</span></ins>
<ol>
<li><ins><span>Evaluates </span><code>flag-&gt;test(order) != old</code><span>.</span></ins></li>
<li><ins><span>If the result of that evaluation is </span><code>true</code><span>, returns </span><code>true</code><span>.</span></ins></li>
<li><ins><span>Otherwise, it has no effects and returns </span><code>false</code><span>.</span></ins><span>.</span></li>
</ol>
</li>
<li><ins><em><span>Remarks</span></em><span>: This function is an atomic waiting operation (</span><a href="http://eel.is/c++draft/atomics.wait" target="_blank" rel="noopener"><span>atomics.wait</span></a><span>).</span></ins></li>
</ul><blockquote>
<p><ins><strong><span>EDITORIAL</span></strong><span>: analogous for the </span><code>atomic_flag_try_wait_for</code><span>/</span><code>_until</code><span> APIs. Intentionally omitted from the current revision of this paper.</span></ins></p>
</blockquote><blockquote>
<p><ins><strong><span>UNRESOLVED QUESTION</span></strong><span>: do we need to change something else for the non-member versions of </span><code>try_wait</code><span>, </span><code>try_wait_for</code><span>, and </span><code>try_wait_until</code><span> operations?</span></ins></p>
</blockquote><blockquote>
<p><ins><strong><span>UNRESOLVED QUESTION</span></strong><span>: do we need to define a “try-wait” atomic operation in </span><a href="http://eel.is/c++draft/atomics.wait" target="_blank" rel="noopener"><span>atomics.wait</span></a><span>? </span></ins></p>
</blockquote><p><span>To [</span><a href="http://eel.is/c++draft/thread.barrier" target="_blank" rel="noopener"><span>thread.barrier</span></a><span>]:</span></p><pre><code>namespace std {
  template &lt;class Completion Function&gt;
  class barrier {
  
  public:
    <ins>bool try_wait(arrival_token&amp;&amp; tok) const;
    template &lt;class Rep, class Period&gt;
    bool try_wait_for(arrival_token&amp;&amp; tok, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time) const;
    template &lt;class Clock, class Duration&gt;
    bool try_wait_until(arrival_token&amp;&amp; tok, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time) const;</ins>
  };
}</code></pre><blockquote>
<p><strong><span>UNRESOLVED QUESTION</span></strong><span>: should we remove </span><code>const</code><span> qualification from the new APIs if </span><a href="http://wg21.link/p2588" target="_blank" rel="noopener"><span>P2588</span></a><span> is accepted?</span></p>
</blockquote><blockquote>
<p><strong><span>EDITORIAL</span></strong><span>: these changes are compatible with both adding </span><code>try_wait</code><span> overloads that accept a </span><code>memory_order</code><span> (</span><a href="http://wg21.link/p2628" target="_blank" rel="noopener"><span>P2628</span></a><span>) and </span><code>try_wait</code><span> overloads that accept a </span><code>bool parity</code><span> instead of an </span><code>arrival_token</code><span> (</span><a href="http://wg21.link/p2629" target="_blank" rel="noopener"><span>P2629</span></a><span>).</span></p>
</blockquote><pre><code><ins>bool try_wait(arrival_token&amp;&amp; arrival) const;</ins></code></pre><ul>
<li><ins><em><span>Preconditions</span></em><span>: </span><code>arrival</code><span> is associated with the phase synchronization point for the current phase or the immediately preceding phase of the same barrier object.</span></ins></li>
<li><ins><em><span>Effects</span></em><span>: If </span><code>arrival</code><span> is associated with the synchronization point for a previous phase, the call returns </span><code>true</code><span> immediately without blocking. Otherwise, there are no effects, and the call returns </span><code>false</code><span>.</span></ins></li>
<li><ins><em><span>Throws</span></em><span>: </span><code>system_error</code><span> when an exception is required (</span><a href="http://eel.is/c++draft/thread.req.exception" target="_blank" rel="noopener"><span>thread.req.exception</span></a><span>).</span></ins></li>
<li><ins><em><span>Error conditions</span></em><span>: Error conditions: Any of the error conditions allowed for mutex types (</span><a href="http://eel.is/c++draft/thread.mutex.requirements.mutex" target="_blank" rel="noopener"><span>thread.mutex.requirements.mutex</span></a><span>).</span></ins></li>
</ul><blockquote>
<p><strong><span>UNRESOLVED QUESTION</span></strong><span>: if </span><a href="http://wg21.link/p2588" target="_blank" rel="noopener"><span>P2588</span></a><span> is accepted, then </span><code>try_wait</code><span> is able to complete the phase and the </span><em><span>Effects</span></em><span> clause needs updating, e.g., as follows: “[…] Otherwise, if all threads have arrived </span><code>try_wait</code><span> may complete the phase and return </span><code>true</code><span>, or the call has no effects and returns </span><code>false</code><span>.”.</span></p>
</blockquote><pre><code><ins>template &lt;class Rep, class Period&gt;
bool try_wait_for(arrival_token&amp;&amp; tok, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time) const;
template &lt;class Clock, class Duration&gt;
bool try_wait_until(arrival_token&amp;&amp; tok, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time) const;</ins></code></pre><blockquote>
<p><strong><span>EDITORIAL</span></strong><span>: </span><code>try_wait_for</code><span> and </span><code>try_wait_until</code><span> shall have analogous semantics.</span></p>
</blockquote><p><span>To </span><a href="http://eel.is/c++draft/thread.latch" target="_blank" rel="noopener"><span>thread.latch</span></a><span>:</span></p><pre><code>namespace std {
  class latch {
  public:
    <ins>template &lt;class Rep, class Period&gt;
    bool try_wait_for(chrono::duration&lt;Rep, Period&gt; const&amp; rel_time) const;
    template &lt;class Clock, class Duration&gt;
    bool try_wait_until(chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time) const;</ins>
  };
}</code></pre><pre><code><ins>template &lt;class Rep, class Period&gt;
bool try_wait_for(chrono::duration&lt;Rep, Period&gt; const&amp; rel_time) const;
template &lt;class Clock, class Duration&gt;
bool try_wait_until(chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time) const;</ins></code></pre><blockquote>
<p><strong><span>EDITORIAL</span></strong><span>: semantics intentionally omitted from the current revision of this paper.</span></p>
</blockquote></div>
    <div class="ui-toc dropup unselectable hidden-print" style="display:none;">
        <div class="pull-right dropdown">
            <a id="tocLabel" class="ui-toc-label btn btn-default" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false" title="Table of content">
                <i class="fa fa-bars"></i>
            </a>
            <ul id="ui-toc" class="ui-toc-dropdown dropdown-menu" aria-labelledby="tocLabel">
                <div class="toc"><ul class="nav">
<li><a href="#Improving-C-concurrency-features" title="Improving C++ concurrency features">Improving C++ concurrency features</a><ul class="nav">
<li><a href="#Revisions" title="Revisions">Revisions</a></li>
<li><a href="#Introduction" title="Introduction">Introduction</a></li>
<li><a href="#Proposed-direction" title="Proposed direction">Proposed direction</a></li>
<li><a href="#Design" title="Design">Design</a></li>
<li><a href="#Wording" title="Wording">Wording</a><ul class="nav">
<li><a href="#Return-last-observed-value-from-atomicwait" title="Return last observed value from atomic::wait">Return last observed value from atomic::wait</a></li>
<li><a href="#Fallible-and-timed-versions-of-wait-APIs" title="Fallible and timed-versions of ::wait APIs">Fallible and timed-versions of ::wait APIs</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
            </ul>
        </div>
    </div>
    <div id="ui-toc-affix" class="ui-affix-toc ui-toc-dropdown unselectable hidden-print" data-spy="affix" style="top:17px;display:none;" null null>
        <div class="toc"><ul class="nav">
<li><a href="#Improving-C-concurrency-features" title="Improving C++ concurrency features">Improving C++ concurrency features</a><ul class="nav">
<li><a href="#Revisions" title="Revisions">Revisions</a></li>
<li><a href="#Introduction" title="Introduction">Introduction</a></li>
<li><a href="#Proposed-direction" title="Proposed direction">Proposed direction</a></li>
<li><a href="#Design" title="Design">Design</a></li>
<li><a href="#Wording" title="Wording">Wording</a><ul class="nav">
<li><a href="#Return-last-observed-value-from-atomicwait" title="Return last observed value from atomic::wait">Return last observed value from atomic::wait</a></li>
<li><a href="#Fallible-and-timed-versions-of-wait-APIs" title="Fallible and timed-versions of ::wait APIs">Fallible and timed-versions of ::wait APIs</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous" defer></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
    <script>
        var markdown = $(".markdown-body");
        //smooth all hash trigger scrolling
        function smoothHashScroll() {
            var hashElements = $("a[href^='#']").toArray();
            for (var i = 0; i < hashElements.length; i++) {
                var element = hashElements[i];
                var $element = $(element);
                var hash = element.hash;
                if (hash) {
                    $element.on('click', function (e) {
                        // store hash
                        var hash = this.hash;
                        if ($(hash).length <= 0) return;
                        // prevent default anchor click behavior
                        e.preventDefault();
                        // animate
                        $('body, html').stop(true, true).animate({
                            scrollTop: $(hash).offset().top
                        }, 100, "linear", function () {
                            // when done, add hash to url
                            // (default click behaviour)
                            window.location.hash = hash;
                        });
                    });
                }
            }
        }

        smoothHashScroll();
        var toc = $('.ui-toc');
        var tocAffix = $('.ui-affix-toc');
        var tocDropdown = $('.ui-toc-dropdown');
        //toc
        tocDropdown.click(function (e) {
            e.stopPropagation();
        });

        var enoughForAffixToc = true;

        function generateScrollspy() {
            $(document.body).scrollspy({
                target: ''
            });
            $(document.body).scrollspy('refresh');
            if (enoughForAffixToc) {
                toc.hide();
                tocAffix.show();
            } else {
                tocAffix.hide();
                toc.show();
            }
            $(document.body).scroll();
        }

        function windowResize() {
            //toc right
            var paddingRight = parseFloat(markdown.css('padding-right'));
            var right = ($(window).width() - (markdown.offset().left + markdown.outerWidth() - paddingRight));
            toc.css('right', right + 'px');
            //affix toc left
            var newbool;
            var rightMargin = (markdown.parent().outerWidth() - markdown.outerWidth()) / 2;
            //for ipad or wider device
            if (rightMargin >= 133) {
                newbool = true;
                var affixLeftMargin = (tocAffix.outerWidth() - tocAffix.width()) / 2;
                var left = markdown.offset().left + markdown.outerWidth() - affixLeftMargin;
                tocAffix.css('left', left + 'px');
            } else {
                newbool = false;
            }
            if (newbool != enoughForAffixToc) {
                enoughForAffixToc = newbool;
                generateScrollspy();
            }
        }
        $(window).resize(function () {
            windowResize();
        });
        $(document).ready(function () {
            windowResize();
            generateScrollspy();
        });

        //remove hash
        function removeHash() {
            window.location.hash = '';
        }

        var backtotop = $('.back-to-top');
        var gotobottom = $('.go-to-bottom');

        backtotop.click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            if (scrollToTop)
                scrollToTop();
            removeHash();
        });
        gotobottom.click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            if (scrollToBottom)
                scrollToBottom();
            removeHash();
        });

        var toggle = $('.expand-toggle');
        var tocExpand = false;

        checkExpandToggle();
        toggle.click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            tocExpand = !tocExpand;
            checkExpandToggle();
        })

        function checkExpandToggle () {
            var toc = $('.ui-toc-dropdown .toc');
            var toggle = $('.expand-toggle');
            if (!tocExpand) {
                toc.removeClass('expand');
                toggle.text('Expand all');
            } else {
                toc.addClass('expand');
                toggle.text('Collapse all');
            }
        }

        function scrollToTop() {
            $('body, html').stop(true, true).animate({
                scrollTop: 0
            }, 100, "linear");
        }

        function scrollToBottom() {
            $('body, html').stop(true, true).animate({
                scrollTop: $(document.body)[0].scrollHeight
            }, 100, "linear");
        }
    </script>
</body>

</html>
