<!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="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.next-editor{overflow-x:hidden!important}.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" data-hard-breaks="true" style=""><p><strong><span>Document number:</span></strong><span> P2643R1</span><br>
<strong><span>Date</span></strong><span>: 2023-05-18</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" style=""><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" style=""><a class="anchor hidden-xs" href="#Revisions" title="Revisions"><span class="octicon octicon-link"></span></a><span>Revisions</span></h2><h3 id="r0---Kona-Drafts" data-id="r0---Kona-Drafts" style=""><a class="anchor hidden-xs" href="#r0---Kona-Drafts" title="r0---Kona-Drafts"><span class="octicon octicon-link"></span></a><span>r0 - (Kona Drafts)</span></h3><ul>
<li><span>Added discussion of pros/cons of returning pair&lt;T. bool&gt; vs. optional</span>&lt;T&gt;<span>.</span></li>
<li><span>Added discussion of timed waits and freestanding, given that </span>&lt;chrono&gt;<span> is not part of freestanding.</span></li>
<li><span>Added wording for </span><code>barrier::try_wait_for</code><span> and </span><code>barrier::try_wait_until</code><span>.</span></li>
<li><span>Added motivating examples.</span></li>
<li><span>Fixed </span><code>barrier::try_wait_for/_until</code><span> signatures; they were incorrectly accepting an </span><code>arrival_token&amp;&amp;</code><span>, but since these can be called in a loop consuming the </span><code>arrival_token</code><span> is incorrect.</span></li>
<li><span>Removed discussion of ‘hinted’ wait mechanism. The design surface area of this proposal is such that it should be a separate paper, brought forward an interested party.</span></li>
<li><span>Removed fallible untimed </span><code>try_wait</code><span>.</span></li>
</ul><h3 id="r1---Varna-Draft" data-id="r1---Varna-Draft" style=""><a class="anchor hidden-xs" href="#r1---Varna-Draft" title="r1---Varna-Draft"><span class="octicon octicon-link"></span></a><span>r1 - (Varna Draft)</span></h3><ul>
<li><span>Removed timed waiting for freestanding, to reflect Kona guidance, and added discussion.</span></li>
<li><span>Removed pros/cons discussion of returning </span><code>optional&lt;T&gt;</code><span> vs </span><code>pair&lt;bool, T&gt;</code><span> vs </span><code>T</code><span>, reflecting Kona guidance.</span></li>
<li><span>Re-added fallible untimed </span><code>try_wait</code><span> with rationale, reflecting Kona guidance.</span></li>
</ul><h2 id="Introduction" data-id="Introduction" style=""><a class="anchor hidden-xs" href="#Introduction" title="Introduction"><span class="octicon octicon-link"></span></a><span>Introduction</span></h2><p><a href="https://wg21.link/p1135r6" target="_blank" rel="noopener"><span>P1135R6</span></a><span> introduced serval new concurrency primitives to the C++20 concurrency library:</span></p><ul>
<li><code>&lt;atomic&gt;</code><span>: added the class </span><code>atomic_flag</code><span>, the </span><code>wait</code><span> and </span><code>notify_one/_all</code><span> to class template </span><code>atomic&lt;&gt;</code><span>, and free function versions of these.</span></li>
<li><code>&lt;semaphore&gt;</code><span>: added class template </span><code>counting_semaphore&lt;&gt;</code><span> and class </span><code>binary_semaphore</code><span>.</span></li>
<li><code>&lt;barrier&gt;</code><span>,</span><code>&lt;latch&gt;</code><span>: added class template </span><code>barrier&lt;&gt;</code><span> and class </span><code>latch</code><span>.</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><ol>
<li><span>Return last observed value from </span><code>atomic::wait</code><span>; this value is lost otherwise.</span></li>
<li><span>Add timed versions of </span><code>atomic::wait</code><span> and other concurrency primitves like </span><code>barrier</code><span> and </span><code>latch</code><span>, to make it easier to implement concurrency primitives on top of </span><code>atomic</code><span> that expose timed waiting facilities themselves, e.g., like </span><code>&lt;semaphore&gt;</code><span>.</span></li>
<li><span>Avoid spurious polling in </span><code>atomic::wait</code><span> by accepting a predicate.</span></li>
</ol><p><span>This proposal proposes extensions to address these shortcomings. This </span><a href="https://gitlab.com/rodgert/gcc/-/commit/dab70764cd68236472656a9394a32185a9ccc890" target="_blank" rel="noopener"><span>branch</span></a><span> demonstrates its implementability in libstdc++.</span></p><h2 id="Design" data-id="Design" style=""><a class="anchor hidden-xs" href="#Design" title="Design"><span class="octicon octicon-link"></span></a><span class="ui-comment-inline-span">Design</span></h2><p><span>The design of the features above is mostly orthogonal, and this section explores them independently.</span></p><h3 id="Return-last-observed-value-on-success" data-id="Return-last-observed-value-on-success" style=""><a class="anchor hidden-xs" href="#Return-last-observed-value-on-success" title="Return-last-observed-value-on-success"><span class="octicon octicon-link"></span></a><span>Return last observed value on success</span></h3><p><span>Desing: </span><code>::wait</code><span> APIs change the return type signature from return</span><span class="ui-comment-inline-span">ing </span><del><code>void</code></del><ins><code>T</code></ins><code> wait(...)</code><span>;</span></p><p><strong><span>Example 0</span></strong><span>:</span></p><table>
<thead>
<tr>
<th><span>Before</span></th>
<th><span>After</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><code>atomic&lt;int&gt; a(42);</code><br><code>a.wait(42);</code><br><code>auto o = a.load();</code><br><code>assert(o != 42); // MAY FAIL!</code></td>
<td><code>atomic&lt;int&gt; a(42);</code><br><code>auto o = a.wait(42);</code><br><br><code>assert(o != 42); // OK!</code></td>
</tr>
</tbody>
</table><p><span>The </span><code>atomic&lt;T&gt;::wait</code><span> method guarantees that the thread is unblocked only if the value changed.</span></p><p><span>Before this paper, the new </span><code>atomic&lt;T&gt;</code><span> value is not returned to the caller. This has the following two shortcomings:</span></p><ul>
<li><strong><span>That value is lost forever</span></strong><span>: after the thread is unblocked, the value might change before the unblocked thread calls </span><code>atomic&lt;T&gt;::load</code><span> (</span><a href="https://en.wikipedia.org/wiki/ABA_problem" target="_blank" rel="noopener"><span>ABA Problem</span></a><span>).</span></li>
<li><strong><span>Applications need the new value often</span></strong><span>: which forces them to call </span><code>atomic&lt;T&gt;::load</code><span>, even though </span><code>atomic::wait&lt;T&gt;</code><span> most likely already loaded the value, to test that it did change.</span></li>
</ul><p><span>After this paper, the value returned by </span><code>wait</code><span> is returned to the caller, eliminating the need for the subsequent load.</span></p><p><span>This is an ABI breaking change that could be resolved by picking a different to-be-determined name for these APIs.</span></p><h3 id="Fallible-and-timed-versions-of-wait-APIs" data-id="Fallible-and-timed-versions-of-wait-APIs" style=""><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 wait APIs</span></h3><p><span>The design of the fallible timed versions of wait APIs adds three new APIs. For </span><code>atomic</code><span> these are</span></p><pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token keyword">template</span> <span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">T</span><span class="token operator">&gt;</span>
optional<span class="token operator">&lt;</span>T<span class="token operator">&gt;</span> <span class="token class-name">atomic</span><span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token double-colon punctuation">::</span><span class="token function">try_wait</span><span class="token punctuation">(</span>T<span class="token punctuation">,</span> memory_order<span class="token punctuation">)</span><span class="token punctuation">;</span>    

<span class="token keyword">template</span> <span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">T</span><span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">Rep</span><span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">Period</span><span class="token operator">&gt;</span>
optional<span class="token operator">&lt;</span>T<span class="token operator">&gt;</span> <span class="token class-name">atomic</span><span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token double-colon punctuation">::</span><span class="token function">try_wait_for</span><span class="token punctuation">(</span>T<span class="token punctuation">,</span> duration<span class="token operator">&lt;</span>Rep<span class="token punctuation">,</span> Period<span class="token operator">&gt;</span> <span class="token keyword">const</span><span class="token operator">&amp;</span><span class="token punctuation">,</span> memory_order<span class="token punctuation">)</span><span class="token punctuation">;</span>
    
<span class="token keyword">template</span> <span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">T</span><span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">Clock</span><span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">Duration</span><span class="token operator">&gt;</span>
optional<span class="token operator">&lt;</span>T<span class="token operator">&gt;</span> <span class="token class-name">atomic</span><span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token double-colon punctuation">::</span><span class="token function">try_wait_until</span><span class="token punctuation">(</span>T<span class="token punctuation">,</span> time_point<span class="token operator">&lt;</span>Clock<span class="token punctuation">,</span> Duration<span class="token operator">&gt;</span> <span class="token keyword">const</span><span class="token operator">&amp;</span><span class="token punctuation">,</span> memory_order<span class="token punctuation">)</span><span class="token punctuation">;</span>
</div></div></code></pre><p><span>They are non-blocking, i.e., they eventually return to the caller in a finite-set of steps, even if the value did not change. This enables the application to “do something else” before attempting to wait again.</span></p><p><span>On failure, i.e., if the value did not change, they return </span><code>nullopt</code><span> and the operation has no effects (it does not synchronize). On success, they return an </span><code>optional&lt;T&gt;</code><span> containing the last observed value, which is guaranteed to be different from the one the call site waited on.</span></p><p><span>The untimed </span><code>try_wait</code><span> overload attempts to wait for a finite </span><em><span>unspecified</span></em><span> duration. The implementation may pick a different duration every time, enabling it decide for how long the operation should attempt to wait based on dynamic information, like the load of the system.</span></p><p><span>Since </span>&lt;chrono&gt;<span> and </span>&lt;optional&gt;<span> are not freestanding, these APIs will not be available in freestanding implementations. We could attempt to improve this by:</span></p><ul>
<li><span>Supporting the subset of </span><code>optional</code><span> APIs that do not throw exceptions in freestanding.</span></li>
<li><span>Supporting the </span><code>&lt;chrono&gt;</code><span> durations in freestanding.</span></li>
</ul><p><strong><span>Example 1</span></strong><span>: the atomic variable </span><code>t</code><span> tracks how many tasks need to still be processed, and the application prints every second - if it is still waiting - how many tasks remain:</span></p><table>
<thead>
<tr>
<th><span>Before</span></th>
<th><span>After</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><code>atomic&lt;int&gt; t;</code><br><code>int old = 1;</code><br><code>auto b = clock::now();</code><br><code>while (old != 0) {</code><br><code> old = t.load();</code><br><code> if (auto e = clock::now(); (e - b) &gt; 1s) {</code><br><code> cout &lt;&lt; old;</code><br><code>    b = e;</code><br><code> }</code><br><code>}</code></td>
<td><code>atomic&lt;int&gt; t;</code><br><code>auto old = 1;</code><br><br><code>while (old != 0) {</code><br><span> </span><code> auto o = t.try_wait_for(old, 1s);</code><br><code>  old = o.has_value()? o.value() : old;</code><br><code> cout &lt;&lt; old;</code><br><code>}</code><br><br><br></td>
</tr>
</tbody>
</table><p><span>Before this proposal, applications need to re-implement </span><code>atomic&lt;T&gt;::wait</code><span> logic, and like in this example, may accidentally call </span><code>atomic&lt;T&gt;::load</code><span> in a loop without any back-off.</span></p><p><span>After this proposal, </span><code>try_wait_for</code><span> expresses the application’s intent to wait for a certain duration of time, enabling the implementation to wait efficiently.</span></p><p><span>For </span><code>barrier</code><span> and </span><code>latch</code><span> they look like:</span></p><pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token keyword">template</span> <span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">CF</span><span class="token operator">&gt;</span>
<span class="token keyword">bool</span> <span class="token class-name">barrier</span><span class="token operator">&lt;</span>CF<span class="token operator">&gt;</span><span class="token double-colon punctuation">::</span><span class="token function">try_wait</span><span class="token punctuation">(</span>arrival_token<span class="token operator">&amp;</span> tok<span class="token punctuation">)</span> <span class="token keyword">const</span><span class="token punctuation">;</span>
<span class="token keyword">template</span> <span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">CF</span><span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">Rep</span><span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">Period</span><span class="token operator">&gt;</span>
<span class="token keyword">bool</span> <span class="token class-name">barrier</span><span class="token operator">&lt;</span>CF<span class="token operator">&gt;</span><span class="token double-colon punctuation">::</span><span class="token function">try_wait_for</span><span class="token punctuation">(</span>arrival_token<span class="token operator">&amp;</span> tok<span class="token punctuation">,</span> duration<span class="token operator">&lt;</span>Rep<span class="token punctuation">,</span> Period<span class="token operator">&gt;</span> <span class="token keyword">const</span><span class="token operator">&amp;</span> rel_time<span class="token punctuation">)</span> <span class="token keyword">const</span><span class="token punctuation">;</span>
<span class="token keyword">template</span> <span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">CF</span><span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">Clock</span><span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">Duration</span><span class="token operator">&gt;</span>
<span class="token keyword">bool</span> <span class="token class-name">barrier</span><span class="token operator">&lt;</span>CF<span class="token operator">&gt;</span><span class="token double-colon punctuation">::</span><span class="token function">try_wait_until</span><span class="token punctuation">(</span>arrival_token<span class="token operator">&amp;</span> tok<span class="token punctuation">,</span> time_point<span class="token operator">&lt;</span>Clock<span class="token punctuation">,</span> Duration<span class="token operator">&gt;</span> <span class="token keyword">const</span><span class="token operator">&amp;</span> abs_time<span class="token punctuation">)</span> <span class="token keyword">const</span><span class="token punctuation">;</span>

<span class="token comment">// Available since C++20</span>
<span class="token comment">// bool latch::try_wait() const noexcept;</span>
<span class="token keyword">template</span> <span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">Rep</span><span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">Period</span><span class="token operator">&gt;</span>
<span class="token keyword">bool</span> latch<span class="token double-colon punctuation">::</span><span class="token function">try_wait_for</span><span class="token punctuation">(</span>duration<span class="token operator">&lt;</span>Rep<span class="token punctuation">,</span> Period<span class="token operator">&gt;</span> <span class="token keyword">const</span><span class="token operator">&amp;</span> rel_time<span class="token punctuation">)</span> <span class="token keyword">const</span><span class="token punctuation">;</span>
<span class="token keyword">template</span> <span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">Clock</span><span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">Duration</span><span class="token operator">&gt;</span>
<span class="token keyword">bool</span> latch<span class="token double-colon punctuation">::</span><span class="token function">try_wait_until</span><span class="token punctuation">(</span>time_point<span class="token operator">&lt;</span>Clock<span class="token punctuation">,</span> Duration<span class="token operator">&gt;</span> <span class="token keyword">const</span><span class="token operator">&amp;</span> abs_time<span class="token punctuation">)</span> <span class="token keyword">const</span><span class="token punctuation">;</span>
</div></div></code></pre><p><strong><span>Example 2</span></strong><span>: using a </span><code>barrier</code><span> which tracks the completion of </span><code>task_count</code><span> tasks:</span></p><pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code">std<span class="token double-colon punctuation">::</span>barrier <span class="token function">b</span><span class="token punctuation">(</span>task_count<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">auto</span> n <span class="token operator">=</span> <span class="token function">process_thread_local_tasks</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
<span class="token keyword">auto</span> t <span class="token operator">=</span> b<span class="token punctuation">.</span><span class="token function">arrive</span><span class="token punctuation">(</span>n<span class="token punctuation">)</span><span class="token punctuation">;</span>
    
<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token operator">!</span>b<span class="token punctuation">.</span><span class="token function">try_wait_for</span><span class="token punctuation">(</span>t<span class="token punctuation">,</span> <span class="token number">1</span>ms<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
   <span class="token keyword">auto</span> s <span class="token operator">=</span> <span class="token function">steal_and_process_tasks</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   b<span class="token punctuation">.</span><span class="token function">arrive</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</div></div></code></pre><h3 id="Predicate-versions" data-id="Predicate-versions" style=""><a class="anchor hidden-xs" href="#Predicate-versions" title="Predicate-versions"><span class="octicon octicon-link"></span></a><span>Predicate versions</span></h3><p><span>There is no wording for the predicate versions proposed in this revision of this paper.</span></p><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><p><span>The authors see two APIs that are both equvialent in terms of implementation complexity and usability, but have an opposite API depending on how the semantics of the predicate are defined.</span></p><p><span>Both options have this signature </span><code>T atomic&lt;T&gt;::wait_with_predicate(Predicate&amp;&amp; p)</code><span> and the predicate takes a </span><code>T</code><span> and returns a </span><code>bool</code><span>, but the predicate returns:</span></p><ul>
<li><span>Option 1: </span><code>true</code><span> if we synchronizes</span>
<ul>
<li><span>Understood as the wait succeds</span></li>
</ul>
</li>
<li><span>Option 2: </span><code>false</code><span> if we synchronizes</span>
<ul>
<li><span>Understood as “the value changed” (value compared not-equal - like </span><code>atomic::wait(T)</code><span> waits until </span><code>T</code><span> changes)</span></li>
</ul>
</li>
</ul><p><strong><span>Feedback needed</span></strong><span>: We should pick an option before working on wording.</span></p><p><strong><span>Example 3</span></strong><span>: same example as Example 1 using Option 1 above (</span><code>true</code><span> if we synchronize):</span></p><table>
<thead>
<tr>
<th><span>Before</span></th>
<th><span>After</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><code>atomic&lt;int&gt; t;</code><br><code>int old = 1;</code><br><code>auto b = clock::now();</code><br><code>while (old != 0) {</code><br><code> old = t.load();</code><br><code> auto e = clock::now();</code><br><code> if ((e - b) &gt; 1s) {</code><br><code> cout &lt;&lt; old;</code><br><code>    b = e;</code><br><code> }</code><br><code>}</code></td>
<td><code>atomic&lt;int&gt; t;</code><br><code>int old = t.load();</code><br><code>auto p = [&amp;](int v) {</code><br><code> old = v;</code><br><code> return v == 0;</code><br><code>};</code><br><br><code>while(!t.try_wait_with_predicate_for(p, 1s).has_value()) {</code><br><code> cout &lt;&lt; old;</code><span> </span><br><code>}</code><br><br></td>
</tr>
</tbody>
</table><p><span>In Example 1, the “After this paper” implementation has the issue that </span><code>try_wait_for(old, 1s)</code><span> returns as soon as </span><code>old</code><span> changes. That is, while the goal of the application is to wait for the value becoming zero, and it could wait up to 1s for that, if after 0.1s the value changes from 10 to 9 this API will return.</span></p><p><span>The “After this paper” implementation in Example 2 fixes that using the fallibe timed </span><code>_with_predicate</code><span> version. The predicate is called every time the value changes, but it doesn’t “succeed” until the value is 0.</span></p><h2 id="Wording" data-id="Wording" style=""><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" style=""><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. Should that be fixed as part of this work?</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-APIs1" data-id="Fallible-and-timed-versions-of-wait-APIs" style=""><a class="anchor hidden-xs" href="#Fallible-and-timed-versions-of-wait-APIs1" title="Fallible-and-timed-versions-of-wait-APIs1"><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(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#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(memory_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 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><br></ins><br>
<ins><span>The timeout for </span><code>try_wait</code><span> is finite but otherwise unspecified.</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(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(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(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(memory_order = memory_order::seq_cst) const 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(memory_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 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(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 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(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 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(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 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(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_for</code><span>/</span><code>_until</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(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_for</code><span>/</span><code>_until</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(memory_order = memory_order::seq_cst) const noexcept;
    bool try_wait(memory_order = memory_order::seq_cst) const noexcept volatile;
    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) noexcept;
bool atomic_flag_try_wait_explicit(const volatile atomic_flag* object, bool old) 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;

bool atomic_flag_try_wait_for(const atomic_flag* object, bool old, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time) noexcept;
bool atomic_flag_try_wait_for(const volatile atomic_flag* object, bool old, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time) noexcept;
bool atomic_flag_try_wait_for_explicit(const atomic_flag* object, bool old, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, memory_order order = memory_order::seq_cst) noexcept;
bool atomic_flag_try_wait_for_explicit(const volatile atomic_flag* object, bool old, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, memory_order order = memory_order::seq_cst) noexcept;
bool atomic_flag::try_wait_for(bool old, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, memory_order order = memory_order::seq_cst) const noexcept;
bool atomic_flag::try_wait_for(bool old, chrono::duration&lt;Rep, Period&gt; const&amp; rel_time, memory_order order = memory_order::seq_cst) const volatile noexcept;

atomic_flag_try_wait_until(const atomic_flag* object, bool old, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time) noexcept;
bool atomic_flag_try_wait_until(const volatile atomic_flag* object, bool old, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time) noexcept;
bool atomic_flag_try_wait_until_explicit(const atomic_flag* object, bool old, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, memory_order order = memory_order::seq_cst) noexcept;
bool atomic_flag_try_wait_until_explicit(const volatile atomic_flag* object, bool old, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, memory_order order = memory_order::seq_cst) noexcept;
bool atomic_flag::try_wait_until(bool old, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time, memory_order order = memory_order::seq_cst) const noexcept;
bool atomic_flag::try_wait_until(bool 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><p><ins><span>For </span><code>atomic_flag_try_wait</code><span>, </span><code>atomic_flag_try_wait_for</code><span>, and </span><code>atomic_flag_try_wait_until</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><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><br></ins><br>
<ins><span>The timeout for </span><code>try_wait</code><span> is finite but otherwise unspecified.</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.wait" target="_blank" rel="noopener"><span>[atomics.wait]</span></a><span>:</span></p><ol start="2">
<li><span>[</span><em><span>Note 2</span></em><span>: The following functions are atomic waiting operations:</span><br>
<span>2.1 </span><code>atomic&lt;T&gt;::wait</code><span>,</span><ins><span> </span><code>atomic&lt;T&gt;::wait_for</code><span>, </span><code>atomic::&lt;T&gt;::wait_until</code><span>,</span></ins><br>
<span>2.2 </span><code>atomic_flag::wait</code><span>, </span><ins><span> </span><code>atomic_flag::wait_for</code><span>, </span><code>atomic_flag::wait_until</code><span>, </span></ins><br>
<span>2.3 </span><code>atomic_wait</code><del><span> and</span></del><ins><span>,</span></ins><span> </span><code>atomic_wait_explicit</code><span>,</span><ins><span> </span><code>atomic_wait_for</code><span>, </span><code>atomic_wait_for_explicit</code><span>, </span><code>atomic_wait_until</code><span>, </span><code>atomic_wait_until_explicit</code><span>,</span></ins><br>
<span>2.4 </span><code>atomic_flag_wait</code><del><span> and</span></del><ins><span>,</span></ins><span> </span><code>atomic_flag_wait_explicit</code><span>, </span><ins><code>atomic_flag_wait_for</code><span>, </span><code>atomic_flag_wait_for_explicit</code><span>, </span><code>atomic_flag_wait_until</code><span>, </span><code>atomic_flag_wait_until_explicit</code><span>,</span></ins><del><span>and</span></del><br>
<span>2.5 </span><code>atomic_ref&lt;T&gt;::wait</code><ins><span>, </span><code>atomic_ref&lt;T&gt;::wait_for</code><span>, </span><code>atomic_ref&lt;T&gt;::wait_until</code></ins><span>.</span><br>
<span>— </span><em><span>end note</span></em><span>]</span></li>
</ol><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_for</code><span> and </span><code>try_wait_until</code><span> operations?</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; tok) const;
    template &lt;class Rep, class Period&gt;
    bool try_wait_for(arrival_token&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; 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>: </span><code>arrival_token&amp;</code><span> vs </span><code>arrival_token const&amp;</code><span> ?</span></p>
<p><span>Note: </span><code>try_wait_for</code><span>/</span><code>try_wait_until</code><span> do not take ownership of the </span><code>arrival_token</code><span> because if they fail, the user still needs the token to be able to call them again.</span></p>
</blockquote><pre><code><ins>bool try_wait(arrival_token&amp; tok) const;
template &lt;class Rep, class Period&gt;
bool try_wait_for(arrival_token&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; tok, chrono::time_point&lt;Clock, Duration&gt; const&amp; abs_time) 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>: Blocks at the synchronization point associated with </span><code>arrival</code><span> until the phase completion step of the synchronization point’s phase is run or the timeout expired. If it is unblocked by the timeout there is no effect and it returns </span><code>false</code><span>; otherwise, it returns </span><code>true</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>The timeout for </span><code>try_wait</code><span> is finite but otherwise unspecified.</span><br></ins><br>
<ins><span>An implementation must ensure that </span><code>try_wait_for</code><span> and </span><code>try_wait_until</code><span> do not consistently return </span><code>false</code><span> after the phase completion step associated with </span><code>arrival</code><span> has run.</span><br></ins><br>
<ins><span>[</span><em><span>Note</span></em><span>: If </span><code>arrival</code><span> is associated with the synchronization point for a previous phase, the call returns immediately. — </span><em><span>end note</span></em><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>) or 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>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><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>bool try_wait() const;
    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>bool try_wait() const;
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 but analogous to </span><code>barrier</code><span>.</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><ul class="nav">
<li><a href="#r0---Kona-Drafts" title="r0 - (Kona Drafts)">r0 - (Kona Drafts)</a></li>
<li><a href="#r1---Varna-Draft" title="r1 - (Varna Draft)">r1 - (Varna Draft)</a></li>
</ul>
</li>
<li><a href="#Introduction" title="Introduction">Introduction</a></li>
<li><a href="#Design" title="Design">Design</a><ul class="nav">
<li><a href="#Return-last-observed-value-on-success" title="Return last observed value on success">Return last observed value on success</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>
<li><a href="#Predicate-versions" title="Predicate versions">Predicate versions</a></li>
</ul>
</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-APIs1" 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><ul class="nav">
<li><a href="#r0---Kona-Drafts" title="r0 - (Kona Drafts)">r0 - (Kona Drafts)</a></li>
<li><a href="#r1---Varna-Draft" title="r1 - (Varna Draft)">r1 - (Varna Draft)</a></li>
</ul>
</li>
<li><a href="#Introduction" title="Introduction">Introduction</a></li>
<li><a href="#Design" title="Design">Design</a><ul class="nav">
<li><a href="#Return-last-observed-value-on-success" title="Return last observed value on success">Return last observed value on success</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>
<li><a href="#Predicate-versions" title="Predicate versions">Predicate versions</a></li>
</ul>
</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-APIs1" 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>
