<!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>
        Hassle-free thread attributes - HackMD
    </title>
    <link rel="icon" type="image/png" href="https://hackmd.io/favicon.png">
    <link rel="apple-touch-icon" href="https://hackmd.io/apple-touch-icon.png">

    <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{border-radius:3px;font-size:85%;line-height:1.45;overflow:auto}.markdown-body:not(.next-editor) pre{background-color:#f7f7f7;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{display:flex;flex-direction:column;gap:16px}.markdown-body .alert>*{margin: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 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>
ins { background-color: #CCFFCC }
s { background-color: #FFCACA }
blockquote { color: inherit !important }
table.no-alt tr:nth-child(2n) { background-color: inherit }
.godbolt {
    background-size: contain;
    background-repeat: no-repeat;
    background-position-y: center;
    background-image: url("https://godbolt.org/favicon.ico?v=1")
}
</style><table><tbody>
<tr><th>Doc. no.:</th>    <td>P3072R1</td></tr>
<tr><th>Date:</th>        <td>2024-2-15</td></tr>
<tr><th>Audience:</th>    <td>LEWG</td></tr>
<tr><th>Reply-to:</th>    <td>Zhihao Yuan &lt;zy@miator.net&gt;</td></tr>
</tbody></table><h1 id="Hassle-free-thread-attributes" data-id="Hassle-free-thread-attributes"><a class="anchor hidden-xs" href="#Hassle-free-thread-attributes" title="Hassle-free-thread-attributes"><span class="octicon octicon-link"></span></a><span>Hassle-free thread attributes</span></h1><p><span class="toc"><ul>
<li><a href="#Hassle-free-thread-attributes" title="Hassle-free thread attributes">Hassle-free thread attributes</a><ul>
<li><a href="#Changes" title="Changes">Changes</a></li>
<li><a href="#Introduction" title="Introduction">Introduction</a></li>
<li><a href="#Motivation" title="Motivation">Motivation</a></li>
<li><a href="#Discussion" title="Discussion">Discussion</a></li>
<li><a href="#Technical-Decisions" title="Technical Decisions">Technical Decisions</a><ul>
<li><a href="#Make-threadattributes-platform-independent" title="Make thread::attributes platform-independent">Make thread::attributes platform-independent</a></li>
<li><a href="#Declare-the-name-attribute-as-string-constamp" title="Declare the name attribute as string const&amp;">Declare the name attribute as string const&amp;</a></li>
<li><a href="#Default-a-template-parameter-to-threadattributes" title="Default a template parameter to thread::attributes">Default a template parameter to thread::attributes</a></li>
<li><a href="#Alias-jthreadattributes-to-threadattributes" title="Alias jthread::attributes to thread::attributes">Alias jthread::attributes to thread::attributes</a></li>
</ul>
</li>
<li><a href="#Implementation" title="Implementation">Implementation</a></li>
<li><a href="#Wording" title="Wording">Wording</a></li>
<li><a href="#References" title="References">References</a></li>
</ul>
</li>
</ul>
</span></p><h2 id="Changes" data-id="Changes"><a class="anchor hidden-xs" href="#Changes" title="Changes"><span class="octicon octicon-link"></span></a><span>Changes</span></h2><dl>
<dt><span>Since R0</span></dt>
<dd>
<ul>
<li><span>Add the wording</span></li>
</ul>
</dd>
</dl><h2 id="Introduction" data-id="Introduction"><a class="anchor hidden-xs" href="#Introduction" title="Introduction"><span class="octicon octicon-link"></span></a><span>Introduction</span></h2><p><span>P2019R5</span><sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup><span> proposes to allow specifying thread attributes, such as name and stack size, when constructing </span><code>std::thread</code><span> and </span><code>std::jthread</code><span>. In such an approach, users express the attributes as objects, one type per attribute. P3022R1</span><sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup><span>, with a mind to standardize the existing practices, groups all standard attributes into one type. In both papers, the types to represent attributes are implementation-defined. This paper proposes a fully specified aggregate to represent all the thread attributes defined by the standard. The vendors can have extra types to carry more or different attributes, as this paper ensures that the different types require differently looking codes.</span></p><p><span>Here is a comparison of the major use cases of the three papers:</span></p><table class="no-alt"><tbody>
<tr><th>
<p><span>P2019</span></p>
</th><td>
<pre><code class="cpp hljs">std<span class="token double-colon punctuation">::</span>jthread <span class="token function">thr</span><span class="token punctuation">(</span>std<span class="token double-colon punctuation">::</span>thread<span class="token double-colon punctuation">::</span><span class="token function">name_hint</span><span class="token punctuation">(</span><span class="token string">"worker"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                 std<span class="token double-colon punctuation">::</span>thread<span class="token double-colon punctuation">::</span><span class="token function">stack_size_hint</span><span class="token punctuation">(</span><span class="token number">16384</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                 <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> std<span class="token double-colon punctuation">::</span><span class="token function">puts</span><span class="token punctuation">(</span><span class="token string">"standard"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<pre><code class="cpp hljs">std<span class="token double-colon punctuation">::</span>jthread <span class="token function">thr</span><span class="token punctuation">(</span>__gnu_cxx<span class="token double-colon punctuation">::</span><span class="token function">posix_schedpolicy</span><span class="token punctuation">(</span>SCHED_FIFO<span class="token punctuation">)</span><span class="token punctuation">,</span>
                 <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> std<span class="token double-colon punctuation">::</span><span class="token function">puts</span><span class="token punctuation">(</span><span class="token string">"vendor extension"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
</td></tr>
<tr><th>
<p><span>P3022</span></p>
</th><td>
<pre><code class="cpp hljs">std<span class="token double-colon punctuation">::</span>jthread<span class="token double-colon punctuation">::</span>attributes attrs<span class="token punctuation">;</span>
attrs<span class="token punctuation">.</span><span class="token function">set_name</span><span class="token punctuation">(</span><span class="token string">"worker"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
attrs<span class="token punctuation">.</span><span class="token function">set_stack_size_hint</span><span class="token punctuation">(</span><span class="token number">16384</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

std<span class="token double-colon punctuation">::</span>jthread <span class="token function">thr</span><span class="token punctuation">(</span>attrs<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> std<span class="token double-colon punctuation">::</span><span class="token function">puts</span><span class="token punctuation">(</span><span class="token string">"standard"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<pre><code class="cpp hljs">__gnu_cxx<span class="token double-colon punctuation">::</span>posix_thread_attributes attrs<span class="token punctuation">;</span>
attrs<span class="token punctuation">.</span><span class="token function">set_schedpolicy</span><span class="token punctuation">(</span>SCHED_FIFO<span class="token punctuation">)</span><span class="token punctuation">;</span>

std<span class="token double-colon punctuation">::</span>jthread <span class="token function">thr</span><span class="token punctuation">(</span>attrs<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> std<span class="token double-colon punctuation">::</span><span class="token function">puts</span><span class="token punctuation">(</span><span class="token string">"vendor extension"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
</td></tr>
<tr><th>
<p><mark><span>P3072</span></mark></p>
</th>
<td>
<pre><code class="cpp hljs">std<span class="token double-colon punctuation">::</span>jthread <span class="token function">thr</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">"worker"</span><span class="token punctuation">,</span> <span class="token punctuation">.</span>stack_size_hint <span class="token operator">=</span> <span class="token number">16384</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
                 <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> std<span class="token double-colon punctuation">::</span><span class="token function">puts</span><span class="token punctuation">(</span><span class="token string">"standard"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<pre><code class="cpp hljs">std<span class="token double-colon punctuation">::</span>jthread <span class="token function">thr</span><span class="token punctuation">(</span>__gnu_cxx<span class="token double-colon punctuation">::</span>posix_thread_attributes<span class="token punctuation">{</span>
                     <span class="token punctuation">.</span>schedpolicy <span class="token operator">=</span> SCHED_FIFO<span class="token punctuation">,</span>
                 <span class="token punctuation">}</span><span class="token punctuation">,</span>
                 <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> std<span class="token double-colon punctuation">::</span><span class="token function">puts</span><span class="token punctuation">(</span><span class="token string">"vendor extension"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
</td></tr>
</tbody></table><h2 id="Motivation" data-id="Motivation"><a class="anchor hidden-xs" href="#Motivation" title="Motivation"><span class="octicon octicon-link"></span></a><span>Motivation</span></h2><p><span>P2019R5</span><sup class="footnote-ref"><a href="#fn1" id="fnref1:1">[1:1]</a></sup><span> has provided excellent motivation for standardizing thread attributes. The rest of this section will focus on the additional motivation for specifying these attributes in an aggregate.</span></p><dl>
<dt><span>Enjoy familiar, natrual, and terse syntax</span></dt>
<dd><span>Attributes are declarative data to most of the programmers. "No two attributes can be of the same type" is an unheard-of restriction, and "calling a subroutine to specify an attribute" is a ubiquitous complication. Designated initializers are already familiar to the C++ users. They precisely specify the attributes, are naturally isolated from the other arguments by the surrounding braces, and are as terse as possible.</span></dd>
<dt><span>Be trivially ABI stable</span></dt>
<dd><span>Changes that can break an aggregate's ABI are apparent and often break API simultaneously; therefore, we won’t make them. We never argue whether </span><code>std::from_chars_result</code><span> is ABI stable. The standard thread attribute aggregate, i.e., </span><code>std::thread::attributes</code><span> in this paper, is meant to be as stable as </span><code>std::from_chars_result</code><span>.</span></dd>
</dl><h2 id="Discussion" data-id="Discussion"><a class="anchor hidden-xs" href="#Discussion" title="Discussion"><span class="octicon octicon-link"></span></a><span>Discussion</span></h2><p><span>The proposed content is compact enough to fit in here for further discussion. First, add a new inner class </span><code>attributes</code><span> in the scope of </span><code>std::thread</code><span>.</span></p><pre data-original-title="" title=""><code class="cpp hljs"><span class="token keyword">class</span> <span class="token class-name">thread</span>
<span class="token punctuation">{</span>
  <span class="token keyword">public</span><span class="token operator">:</span>
    <span class="token keyword">struct</span> <span class="token class-name">attributes</span>
    <span class="token punctuation">{</span>
        std<span class="token double-colon punctuation">::</span>string <span class="token keyword">const</span> <span class="token operator">&amp;</span>name <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
        std<span class="token double-colon punctuation">::</span>size_t stack_size_hint <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>

    …
</code></pre><p><span>And then, add extra constructors to </span><code>std::thread</code><span> and </span><code>std::jthread</code><span>, one for each.</span></p><pre><code class="cpp hljs"><span class="token keyword">class</span> <span class="token class-name">thread</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">Attrs</span> <span class="token operator">=</span> attributes<span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">F</span><span class="token punctuation">,</span> <span class="token keyword">class</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> Args<span class="token operator">&gt;</span>
        <span class="token keyword">requires</span> std<span class="token double-colon punctuation">::</span>is_invocable_v<span class="token operator">&lt;</span>F<span class="token punctuation">,</span> Args<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token operator">&gt;</span>
    <span class="token keyword">explicit</span> <span class="token function">thread</span><span class="token punctuation">(</span>Attrs<span class="token punctuation">,</span> F <span class="token operator">&amp;&amp;</span><span class="token punctuation">,</span> Args <span class="token operator">&amp;&amp;</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    …
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">class</span> <span class="token class-name">jthread</span>
<span class="token punctuation">{</span>
    …
    <span class="token keyword">using</span> attributes <span class="token operator">=</span> thread<span class="token double-colon punctuation">::</span>attributes<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">Attrs</span> <span class="token operator">=</span> attributes<span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">F</span><span class="token punctuation">,</span> <span class="token keyword">class</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> Args<span class="token operator">&gt;</span>
        <span class="token keyword">requires</span> std<span class="token double-colon punctuation">::</span>is_invocable_v<span class="token operator">&lt;</span>F<span class="token punctuation">,</span> Args<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token operator">&gt;</span>
    <span class="token keyword">explicit</span> <span class="token function">jthread</span><span class="token punctuation">(</span>Attrs<span class="token punctuation">,</span> F <span class="token operator">&amp;&amp;</span><span class="token punctuation">,</span> Args <span class="token operator">&amp;&amp;</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    …
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><p><span>They enable a variety of uses.</span></p><dl>
<dt><span>Specifying all standard thread attributes</span></dt>
<dd>
<pre><code class="cpp hljs">std<span class="token double-colon punctuation">::</span>thread <span class="token function">t1</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">.</span>name <span class="token operator">=</span> std<span class="token double-colon punctuation">::</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"worker {}"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span>stack_size_hint <span class="token operator">=</span> <span class="token number">16384</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
               <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> std<span class="token double-colon punctuation">::</span><span class="token function">puts</span><span class="token punctuation">(</span><span class="token string">"everything"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<span>As designators, neither attribute can repeat in the same list; </span><code>.name</code><span> must precede </span><code>.stack_size_hint</code><span> if both appear.</span></dd>
<dt><span>Specifying only the thread name</span></dt>
<dd>
<pre><code class="cpp hljs">std<span class="token double-colon punctuation">::</span>thread <span class="token function">t2</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">"gui"</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> std<span class="token double-colon punctuation">::</span><span class="token function">puts</span><span class="token punctuation">(</span><span class="token string">"only name"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<code>stack_size_hint</code><span> has no effect if it compares equal to 0.</span></dd>
<dt><span>Providing only a hint to the stack size</span></dt>
<dd>
<pre><code class="cpp hljs">std<span class="token double-colon punctuation">::</span>thread <span class="token function">t3</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">.</span>stack_size_hint <span class="token operator">=</span> <span class="token number">4096</span><span class="token punctuation">}</span><span class="token punctuation">,</span> std<span class="token double-colon punctuation">::</span>puts<span class="token punctuation">,</span> <span class="token string">"only size"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<code>name</code><span> has no effect if it is an empty string.</span></dd>
<dt><span>Declaring the attributes object as a variable</span></dt>
<dd>
<pre><code class="cpp hljs">std<span class="token double-colon punctuation">::</span>thread<span class="token double-colon punctuation">::</span>attributes attrs<span class="token punctuation">{</span><span class="token punctuation">.</span>name <span class="token operator">=</span> std<span class="token double-colon punctuation">::</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"worker {}"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
std<span class="token double-colon punctuation">::</span>thread <span class="token function">t4</span><span class="token punctuation">(</span>attrs<span class="token punctuation">,</span> std<span class="token double-colon punctuation">::</span>puts<span class="token punctuation">,</span> <span class="token string">"lifetime extension"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<span>Member of reference type extends the lifetime of its initializer in a braced aggregate initialization. Replacing the braces with parenthesizes loses lifetime extension, but designated initializers cannot appear inside parenthesizes in the first place.</span></dd>
<dt><span>Substituting in non-standard thread attributes</span></dt>
<dd>
<pre><code class="cpp hljs">std<span class="token double-colon punctuation">::</span>thread <span class="token function">t5</span><span class="token punctuation">(</span>__gnu_cxx<span class="token double-colon punctuation">::</span>posix_thread_attributes<span class="token punctuation">{</span><span class="token punctuation">.</span>schedpolicy <span class="token operator">=</span> SCHED_FIFO<span class="token punctuation">}</span><span class="token punctuation">,</span>
               std<span class="token double-colon punctuation">::</span>puts<span class="token punctuation">,</span> <span class="token string">"vendor extension"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<span>The users cannot omit the type names for the non-standard attributes in front of the </span><em><span>braced-init-list</span></em><span>.</span></dd>
</dl><p><code>std::jthread</code><span> offers the same capability.</span></p><h2 id="Technical-Decisions" data-id="Technical-Decisions"><a class="anchor hidden-xs" href="#Technical-Decisions" title="Technical-Decisions"><span class="octicon octicon-link"></span></a><span>Technical Decisions</span></h2><h3 id="Make-threadattributes-platform-independent" data-id="Make-threadattributes-platform-independent"><a class="anchor hidden-xs" href="#Make-threadattributes-platform-independent" title="Make-threadattributes-platform-independent"><span class="octicon octicon-link"></span></a><span>Make </span><code>thread::attributes</code><span> platform-independent</span></h3><p><span>In a survey from P3022</span><sup class="footnote-ref"><a href="#fn2" id="fnref2:1">[2:1]</a></sup><span>, Boost.Thread stores OS-provided thread attribute handle in </span><code>boost::thread::attributes</code><span> on certain platforms. More specifically, </span><code>pthread_attr_t</code><span> on POSIX. This may give the audiences a misconception </span><span class="smartypants">–</span><span> the thread name may be managed by an opaque type so that a standard library implementation doesn't need to allocate anything extra for that string. This is not true. A table in P2019 shows that no platform supports an attribute handle of that design. And </span><code>Boost.Thread</code><span> only supports setting the stack size, which is the least motivating attribute to be represented platform-dependently.</span></p><p><span>Since thread names often come with a 15-character limit on non-Windows platforms, do we want different guts when implementing the name attribute on different platforms, then?</span></p><pre><code class="cpp hljs"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">if</span> <span class="token expression"><span class="token function">defined</span><span class="token punctuation">(</span>_WIN32<span class="token punctuation">)</span></span></span>
    unique_ptr<span class="token operator">&lt;</span><span class="token keyword">char</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span> name_<span class="token punctuation">;</span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">else</span></span>
    <span class="token keyword">char</span> name_<span class="token punctuation">[</span><span class="token number">16</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">endif</span></span>
</code></pre><p><span>It turns out that </span><code>std::string</code><span> offers this, and only better. Therefore, using </span><code>std::string</code><span> in some form is entirely acceptable when specifying the thread name.</span></p><p><span>The motivation for making </span><strong><span>standard</span></strong><span> thread attribute types implementation-defined is weak. A </span><code>thread::attributes</code><span> that reuses existing standard library types brings less hassle when working with. Consequently, </span><code>thread::attributes</code><span> should be platform-independent in a given standard library implementation.</span></p><h3 id="Declare-the-name-attribute-as-string-constamp" data-id="Declare-the-name-attribute-as-string-constamp"><a class="anchor hidden-xs" href="#Declare-the-name-attribute-as-string-constamp" title="Declare-the-name-attribute-as-string-constamp"><span class="octicon octicon-link"></span></a><span>Declare the </span><code>name</code><span> attribute as </span><code>string const&amp;</code></h3><p><span>In a prior discussion of P2019, LEWG concluded that thread attributes may depend on runtime values in many cases, such as thread names formatted with a counter. In today's C++ standard, the best practice for creating strings of that kind is to use </span><code>std::format</code><span>. Therefore, the full solution to thread attributes must be optimal when combined with </span><code>std::format</code><span>.</span></p><p><span>If the </span><code>name</code><span> member of </span><code>std::thread::attributes</code><span> is of type </span><code>char const*</code><span>, one must call </span><code>.c_str()</code><span> or an equivalent member function on the result of </span><code>std::format</code><span>. The code to initialize is not only bumpy but also invites dangling pointers:</span></p><pre><code class="cpp hljs">std<span class="token double-colon punctuation">::</span>thread<span class="token double-colon punctuation">::</span>attributes attrs<span class="token punctuation">{</span><span class="token punctuation">.</span>name <span class="token operator">=</span> std<span class="token double-colon punctuation">::</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"worker {}"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// dangling</span>
</code></pre><p><span>If </span><code>name</code><span> is declared </span><code>string_view</code><span>, the dangling error hides even better:</span></p><pre><code class="cpp hljs">std<span class="token double-colon punctuation">::</span>thread<span class="token double-colon punctuation">::</span>attributes attrs<span class="token punctuation">{</span><span class="token punctuation">.</span>name <span class="token operator">=</span> std<span class="token double-colon punctuation">::</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"worker {}"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">;</span>    <span class="token comment">// also dangling</span>
</code></pre><p><span>Moreover, as a survey from P2019 suggested, all platforms expect thread names to be null-terminated. </span><code>string_view</code><span> does not guarantee its content to be null-terminated and requires extra work in the </span><code>thread</code><span> and </span><code>jthread</code><span> constructors.</span></p><p><span>If </span><code>name</code><span> is declared </span><code>string</code><span>, the last code snippet won't be dangling. However, the size of the </span><code>attributes</code><span> struct will be doubled. The type won't be trivial, will require more work to be moved or copied, and can easily trigger a copy:</span></p><pre><code class="cpp hljs"><span class="token keyword">auto</span> <span class="token function">launch_first</span><span class="token punctuation">(</span>std<span class="token double-colon punctuation">::</span>vector<span class="token operator">&lt;</span>std<span class="token double-colon punctuation">::</span>string<span class="token operator">&gt;</span> <span class="token keyword">const</span><span class="token operator">&amp;</span> names<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">return</span> std<span class="token double-colon punctuation">::</span><span class="token function">thread</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">.</span>name <span class="token operator">=</span> names<span class="token punctuation">.</span><span class="token function">front</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p><span>Declaring </span><code>name</code><span> as </span><code>string const&amp;</code><span> has none of the aforementioned issues.</span></p><h3 id="Default-a-template-parameter-to-threadattributes" data-id="Default-a-template-parameter-to-threadattributes"><a class="anchor hidden-xs" href="#Default-a-template-parameter-to-threadattributes" title="Default-a-template-parameter-to-threadattributes"><span class="octicon octicon-link"></span></a><span>Default a template parameter to </span><code>thread::attributes</code></h3><p><span>Assigning the default argument of a template parameter </span><code>T</code><span> to an aggregate enables braced initialization of an argument for a function parameter of type </span><code>T</code><span> without filling out the type name of the aggregate at the caller site. Declaring that function parameter as the aggregate has the same effect. So, can we allow vendor extensions by building an overload set?</span></p><table class="no-alt"><tbody>
<tr><th>
<p><span>P3072</span></p>
</th><td>
<pre><code class="cpp hljs"><span class="token keyword">template</span><span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">Attrs</span> <span class="token operator">=</span> attributes<span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">F</span><span class="token punctuation">,</span> <span class="token keyword">class</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> Args<span class="token operator">&gt;</span>
    <span class="token keyword">requires</span> is_invocable_v<span class="token operator">&lt;</span>F<span class="token punctuation">,</span> Args<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token operator">&gt;</span>
<span class="token keyword">explicit</span> <span class="token function">thread</span><span class="token punctuation">(</span>Attrs<span class="token punctuation">,</span> F <span class="token operator">&amp;&amp;</span><span class="token punctuation">,</span> Args <span class="token operator">&amp;&amp;</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
</td></tr>
<tr><th>
<p><mark><span>Alt.</span></mark></p>
</th>
<td>
<pre><code class="cpp hljs"><span class="token keyword">template</span><span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">F</span><span class="token punctuation">,</span> <span class="token keyword">class</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> Args<span class="token operator">&gt;</span>
<span class="token keyword">explicit</span> <span class="token function">thread</span><span class="token punctuation">(</span>attributes<span class="token punctuation">,</span> F <span class="token operator">&amp;&amp;</span><span class="token punctuation">,</span> Args <span class="token operator">&amp;&amp;</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><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">F</span><span class="token punctuation">,</span> <span class="token keyword">class</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> Args<span class="token operator">&gt;</span>
<span class="token keyword">explicit</span> <span class="token function">thread</span><span class="token punctuation">(</span>__extended_thread_attributes<span class="token punctuation">,</span> F <span class="token operator">&amp;&amp;</span><span class="token punctuation">,</span> Args <span class="token operator">&amp;&amp;</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
</td></tr>
</tbody></table><p><span>Unsurprisingly, there is a critical difference. If </span><code>__extended_thread_attributes</code><span> is declared like this,</span></p><pre><code class="cpp hljs"><span class="token keyword">struct</span> <span class="token class-name">__extended_thread_attributes</span>
<span class="token punctuation">{</span>
    <span class="token keyword">char</span> name<span class="token punctuation">[</span><span class="token number">16</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    size_t stack <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> schedpolicy <span class="token operator">=</span> SCHED_OTHER<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><p><span>the following code will become ill-formed with the alternative design because the call is ambiguous.</span></p><pre><code class="cpp hljs">std<span class="token double-colon punctuation">::</span>thread <span class="token function">t2</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">"gui"</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> std<span class="token double-colon punctuation">::</span><span class="token function">puts</span><span class="token punctuation">(</span><span class="token string">"only name"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p><span>If we were to pursue this design, name conflicts between the standard thread attributes, vendor extended attributes, and future standard thread attributes would have to be resolved at the member level.</span></p><p><span>The proposed design avoids this type of ambiguity by construction. The declarion above initializes only </span><code>std::thread::attributes</code><span>.</span></p><h3 id="Alias-jthreadattributes-to-threadattributes" data-id="Alias-jthreadattributes-to-threadattributes"><a class="anchor hidden-xs" href="#Alias-jthreadattributes-to-threadattributes" title="Alias-jthreadattributes-to-threadattributes"><span class="octicon octicon-link"></span></a><span>Alias </span><code>jthread::attributes</code><span> to </span><code>thread::attributes</code></h3><p><span>Doing so won't be the reason that prevents us from evolving </span><code>jthread::attributes</code><span> independently from </span><code>thread::attributes</code><span> because adding a member to a public aggregate defined in the standard is not an option to begin with. This also means if we do want the content of </span><code>jthread::attributes</code><span> and </span><code>thread::attributes</code><span> to diverge, the decision must be made now. But as time of writing, we see no motivation in such a direction.</span></p><p><span>Allowing a variable declared </span><code>std::thread::attributes</code><span> to be shared by both </span><code>std::thread</code><span> and </span><code>std::jthread</code><span> constructors looks entirely acceptable. This also avoids the headache of debating the effect of the following code:</span></p><pre><code class="cpp hljs">std<span class="token double-colon punctuation">::</span>thread<span class="token double-colon punctuation">::</span>attributes attrs<span class="token punctuation">{</span><span class="token punctuation">.</span>name <span class="token operator">=</span> std<span class="token double-colon punctuation">::</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"worker {}"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
std<span class="token double-colon punctuation">::</span>jthread <span class="token function">t</span><span class="token punctuation">(</span>attrs<span class="token punctuation">,</span> std<span class="token double-colon punctuation">::</span>puts<span class="token punctuation">,</span> <span class="token string">"ignored, ill-formed, or vendor extension?"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><h2 id="Implementation" data-id="Implementation"><a class="anchor hidden-xs" href="#Implementation" title="Implementation"><span class="octicon octicon-link"></span></a><span>Implementation</span></h2><p><span>P2019R5</span><sup class="footnote-ref"><a href="#fn1" id="fnref1:2">[1:2]</a></sup><span> has discussed the implementability of platform-independent thread names and stack size hints.</span></p><p><span>Here is a playground to demonstrate the proposed interface of this paper: </span><ruby><a href="https://godbolt.org/z/jban3hG37" target="_blank" rel="noopener"><span class="godbolt"><span> </span></span><span>jban3hG37</span></a><rt><span>Compiler Explorer</span></rt></ruby></p><p><span>Combining these should give us a complete implementation.</span></p><h2 id="Wording" data-id="Wording"><a class="anchor hidden-xs" href="#Wording" title="Wording"><span class="octicon octicon-link"></span></a><span>Wording</span></h2><p><span>The wording is relative to </span><a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4971.pdf" target="_blank" rel="noopener"><span>N4971</span></a><span>.</span></p><p><span>In </span><a href="https://eel.is/c++draft/thread.thread.class.general" target="_blank" rel="noopener"><span>[thread.thread.class.general]</span></a><span>, modify the synposis in the first paragraph as follows:</span></p><pre>namespace std {
  class thread {
  public:
    <i>// [thread.thread.id], class</i> thread::id
    class id;
    using native_handle_type = implementation-defined;  <i>// see [thread.req.native]</i>
<ins>    struct attributes {
        string const&amp; name = {};
        size_t stack_size_hint = 0;
    };</ins>

    <i>// construct/copy/destroy</i>
    thread() noexcept;
    template&lt;class F, class... Args&gt; explicit thread(F&amp;&amp; f, Args&amp;&amp;... args);
<ins>    template&lt;class Attrs = attributes, class F, class... Args&gt;
      explicit thread(Attrs, F&amp;&amp;, Args&amp;&amp;...);</ins>
    ~thread();
</pre><p><span>Append the following paragraph after </span><a href="https://eel.is/c++draft/thread.thread.class.general#1" target="_blank" rel="noopener"><span>[thread.thread.class.general]/1</span></a><span>:</span></p><blockquote>
<p><ins><span>The type </span><code>attributes</code><span> have the data members, their default member initializers, and special members specified above. They have no base classes or members other than those specified.</span></ins></p>
</blockquote><p><span>Modify </span><a href="https://eel.is/c++draft/thread.thread.constr" target="_blank" rel="noopener"><span>[thread.thread.constr]</span></a><span> as follows:</span></p><pre>thread() noexcept;
</pre><blockquote>
<p><em><span>Effects:</span></em><span> The object does not represent a thread of execution.</span></p>
<p><em><span>Postconditions:</span></em><span> </span><code>get_id() == id()</code><span>.</span></p>
</blockquote><pre>template&lt;class F, class... Args&gt; explicit thread(F&amp;&amp; f, Args&amp;&amp;... args);
<ins>template&lt;class Attrs = attributes, class F, class... Args&gt;
  explicit thread(Attrs attrs, F&amp;&amp; f, Args&amp;&amp;... args);</ins>
</pre><blockquote data-original-title="" title="">
<p><em><span>Constraints:</span></em><span> </span><code>remove_cvref_t&lt;F&gt;</code><span> is not the same type as </span><code>thread</code><span> </span><ins><span>and </span><code>is_invocable_v&lt;decay_t&lt;F&gt;, decay_t&lt;Args&gt;...&gt;</code><span> is </span><code>true</code></ins><span>.</span></p>
<p><em><span>Mandates:</span></em><span> The following are all </span><code>true</code><span>:</span></p>
<ul>
<li><code>is_constructible_v&lt;decay_t&lt;F&gt;, F&gt;</code><span>,</span></li>
<li><code>(is_constructible_v&lt;decay_t&lt;Args&gt;, Args&gt; &amp;&amp; ...)</code><s><span>, and</span></s></li>
<li><s><code>is_invocable_v&lt;decay_t&lt;F&gt;, decay_t&lt;Args&gt;...&gt;</code></s><span>.</span></li>
</ul>
<p><em><span>Effects:</span></em><span> The new thread of execution executes</span></p>
<p><span>&nbsp;&nbsp;</span><code style="white-space: pre-wrap"><span>invoke(auto(std::forward&lt;F&gt;(f)),  </span><i><span>// for</span></i><span> invoke</span><i><span>, see [func.invoke]</span></i></code><br>
<span>&nbsp;&nbsp;</span><code style="white-space: pre-wrap"><span>       auto(std::forward&lt;Args&gt;(args))...)</span></code></p>
<p><span>with the values produced by </span><code>auto</code><span> being materialized (</span><a href="https://eel.is/c++draft/conv.rval" target="_blank" rel="noopener"><span>[conv.rval]</span></a><span>) in the constructing thread. Any return value from this invocation is ignored.</span></p>
<p><em><span>[Note 1:</span></em><span> This implies that any exceptions not thrown from the invocation of the copy of </span><code>f</code><span> will be thrown in the constructing thread, not the new thread. </span><em><span class="smartypants">–</span><span>end note]</span></em></p>
<p><span>If the invocation of invoke terminates with an uncaught exception, terminate is invoked (</span><a href="https://eel.is/c++draft/except.terminate" target="_blank" rel="noopener"><span>[except.terminate]</span></a><span>).</span></p>
<p><ins><span>The parameter </span><code>attrs</code><span> can be used to tailor the new thread with implementation-defined properties that do not alter the semantics of its execution. An implementation may accept </span><code>attrs</code><span> of additional types other than </span><code>thread::attributes</code><span>.</span></ins></p>
<p><ins><em><span>[Note 2:</span></em><span> When </span><code>attrs</code><span> is of type </span><code>thread::attributes</code><span>, an implementation may derive the name for the new thread for debugging or platform-specific display mechanisms from </span><code>attrs.name</code><span> and may set an initial stack size based on </span><code>attrs.stack_size_hint</code><span>. </span><em><span class="smartypants">–</span><span>end note]</span></em></ins></p>
<p><ins><em><span>Recommended practice:</span></em><span> Implementations should avoid storing the value of </span><code>attrs</code><span> in the </span><code>thread</code><span> object.</span></ins></p>
<p><span>[</span><span class="smartypants">…</span><span>]</span></p>
</blockquote><p><span>In </span><a href="https://eel.is/c++draft/thread.jthread.class.general" target="_blank" rel="noopener"><span>[thread.jthread.class.general]</span></a><span>, modify the synposis as follows:</span></p><pre>namespace std {
  class jthread {
  public:
    <i>// types</i>
    using id = thread::id;
    using native_handle_type = thread::native_handle_type;
<ins>    using attributes = thread::attributes;</ins>

    <i>// [thread.jthread.cons], constructors, move, and assignment</i>
    jthread() noexcept;
    template&lt;class F, class... Args&gt; explicit jthread(F&amp;&amp; f, Args&amp;&amp;... args);
<ins>    template&lt;class Attrs = attributes, class F, class... Args&gt;
      explicit jthread(Attrs, F&amp;&amp;, Args&amp;&amp;...);</ins>
    ~jthread();
</pre><p><span>Modify </span><a href="https://eel.is/c++draft/thread.jthread.cons" target="_blank" rel="noopener"><span>[thread.jthread.cons]</span></a><span> as follows:</span></p><pre>jthread() noexcept;
</pre><blockquote>
<p><em><span>Effects:</span></em><span> Constructs a </span><code>jthread</code><span> object that does not represent a thread of execution.</span></p>
<p><em><span>Postconditions:</span></em><span> </span><code>get_id() == id()</code><span> is </span><code>true</code><span> and </span><code>ssource.stop_possible()</code><span> is </span><code>false</code><span>.</span></p>
</blockquote><pre>template&lt;class F, class... Args&gt; explicit jthread(F&amp;&amp; f, Args&amp;&amp;... args);
<ins>template&lt;class Attrs = attributes, class F, class... Args&gt;
  explicit jthread(Attrs attrs, F&amp;&amp; f, Args&amp;&amp;... args);</ins>
</pre><blockquote>
<p><em><span>Constraints:</span></em><span> </span><code>remove_cvref_t&lt;F&gt;</code><span> is not the same type as </span><code>jthread</code><span> </span><ins><span>and</span><br>
<code>is_invocable_v&lt;decay_t&lt;F&gt;, decay_t&lt;Args&gt;...&gt; ||  is_invocable_v&lt;decay_t&lt;F&gt;, stop_token, decay_t&lt;Args&gt;...&gt;</code><span> is </span><code>true</code></ins><span>.</span></p>
<p><em><span>Mandates:</span></em><span> The following are all </span><code>true</code><span>:</span></p>
<ul>
<li><code>is_constructible_v&lt;decay_t&lt;F&gt;, F&gt;</code><span>,</span></li>
<li><code>(is_constructible_v&lt;decay_t&lt;Args&gt;, Args&gt; &amp;&amp; ...)</code><s><span>, and</span></s></li>
<li><s><code>is_invocable_v&lt;decay_t&lt;F&gt;, decay_t&lt;Args&gt;...&gt; ||  is_invocable_v&lt;decay_t&lt;F&gt;, stop_token, decay_t&lt;Args&gt;...&gt;</code></s><span>.</span></li>
</ul>
<p><em><span>Effects:</span></em><span> Initializes </span><code>ssource</code><span>. The new thread of execution executes</span></p>
<p><span>&nbsp;&nbsp;</span><code style="white-space: pre-wrap"><span>invoke(auto(std::forward&lt;F&gt;(f)), get_stop_token(),  </span><i><span>// for</span></i><span> invoke</span><i><span>, see [func.invoke]</span></i></code><br>
<span>&nbsp;&nbsp;</span><code style="white-space: pre-wrap"><span>       auto(std::forward&lt;Args&gt;(args))...)</span></code></p>
<p><span>if that expression is well-formed, otherwise</span></p>
<p><span>&nbsp;&nbsp;</span><code style="white-space: pre-wrap"><span>invoke(auto(std::forward&lt;F&gt;(f)), auto(std::forward&lt;Args&gt;(args))...)</span></code></p>
<p><span>with the values produced by </span><code>auto</code><span> being materialized (</span><a href="https://eel.is/c++draft/conv.rval" target="_blank" rel="noopener"><span>[conv.rval]</span></a><span>) in the constructing thread. Any return value from this invocation is ignored.</span></p>
<p><em><span>[Note 1:</span></em><span> This implies that any exceptions not thrown from the invocation of the copy of </span><code>f</code><span> will be thrown in the constructing thread, not the new thread. </span><em><span class="smartypants">–</span><span>end note]</span></em></p>
<p><span>If the </span><code>invoke</code><span> expression exits via an exception, </span><code>terminate</code><span> is called.</span></p>
<p><ins><span>The parameter </span><code>attrs</code><span> can be used to tailor the new thread with implementation-defined properties that do not alter the semantics of its execution. An implementation may accept </span><code>attrs</code><span> of additional types other than </span><code>thread::attributes</code><span>.</span></ins></p>
<p><ins><em><span>[Note 2:</span></em><span> When </span><code>attrs</code><span> is of type </span><code>thread::attributes</code><span>, an implementation may derive the name for the new thread for debugging or platform-specific display mechanisms from </span><code>attrs.name</code><span> and may set an initial stack size based on </span><code>attrs.stack_size_hint</code><span>. </span><em><span class="smartypants">–</span><span>end note]</span></em></ins></p>
<p><ins><em><span>Recommended practice:</span></em><span> Implementations should avoid storing the value of </span><code>attrs</code><span> in the </span><code>jthread</code><span> object.</span></ins></p>
<p><span>[</span><span class="smartypants">…</span><span>]</span></p>
</blockquote><h2 id="References" data-id="References"><a class="anchor hidden-xs" href="#References" title="References"><span class="octicon octicon-link"></span></a><span>References</span></h2><hr class="footnotes-sep"><section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><span>P2019R5 </span><em><span>Thread attributes.</span></em><br>
<a href="https://wg21.link/p2019r5" target="_blank" rel="noopener"><span>https://wg21.link/p2019r5</span></a> <a href="#fnref1" class="footnote-backref">↩︎</a> <a href="#fnref1:1" class="footnote-backref">↩︎</a> <a href="#fnref1:2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p><span>P3022R1 </span><em><span>A Boring Thread Attributes Interface.</span></em><br>
<a href="https://wg21.link/p3022r1" target="_blank" rel="noopener"><span>https://wg21.link/p3022r1</span></a> <a href="#fnref2" class="footnote-backref">↩︎</a> <a href="#fnref2:1" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section></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="#Hassle-free-thread-attributes" title="Hassle-free thread attributes">Hassle-free thread attributes</a><ul class="nav">
<li><a href="#Changes" title="Changes">Changes</a></li>
<li><a href="#Introduction" title="Introduction">Introduction</a></li>
<li><a href="#Motivation" title="Motivation">Motivation</a></li>
<li><a href="#Discussion" title="Discussion">Discussion</a></li>
<li><a href="#Technical-Decisions" title="Technical Decisions">Technical Decisions</a><ul class="nav">
<li><a href="#Make-threadattributes-platform-independent" title="Make thread::attributes platform-independent">Make thread::attributes platform-independent</a></li>
<li><a href="#Declare-the-name-attribute-as-string-constamp" title="Declare the name attribute as string const&amp;">Declare the name attribute as string const&amp;</a></li>
<li><a href="#Default-a-template-parameter-to-threadattributes" title="Default a template parameter to thread::attributes">Default a template parameter to thread::attributes</a></li>
<li><a href="#Alias-jthreadattributes-to-threadattributes" title="Alias jthread::attributes to thread::attributes">Alias jthread::attributes to thread::attributes</a></li>
</ul>
</li>
<li><a href="#Implementation" title="Implementation">Implementation</a></li>
<li><a href="#Wording" title="Wording">Wording</a></li>
<li><a href="#References" title="References">References</a></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 class=""><a href="#Hassle-free-thread-attributes" title="Hassle-free thread attributes">Hassle-free thread attributes</a><ul class="nav">
<li class=""><a href="#Changes" title="Changes">Changes</a></li>
<li class=""><a href="#Introduction" title="Introduction">Introduction</a></li>
<li class=""><a href="#Motivation" title="Motivation">Motivation</a></li>
<li class=""><a href="#Discussion" title="Discussion">Discussion</a></li>
<li class=""><a href="#Technical-Decisions" title="Technical Decisions">Technical Decisions</a><ul class="nav">
<li class=""><a href="#Make-threadattributes-platform-independent" title="Make thread::attributes platform-independent">Make thread::attributes platform-independent</a></li>
<li class=""><a href="#Declare-the-name-attribute-as-string-constamp" title="Declare the name attribute as string const&amp;">Declare the name attribute as string const&amp;</a></li>
<li class=""><a href="#Default-a-template-parameter-to-threadattributes" title="Default a template parameter to thread::attributes">Default a template parameter to thread::attributes</a></li>
<li class=""><a href="#Alias-jthreadattributes-to-threadattributes" title="Alias jthread::attributes to thread::attributes">Alias jthread::attributes to thread::attributes</a></li>
</ul>
</li>
<li class=""><a href="#Implementation" title="Implementation">Implementation</a></li>
<li class=""><a href="#Wording" title="Wording">Wording</a></li>
<li class=""><a href="#References" title="References">References</a></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>
