[{"data":1,"prerenderedAt":5183},["ShallowReactive",2],{"wiki-page-\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-1600-jthread-stop-token":3,"wiki-doc-items-2023-10-05-cplusplus-jiao-xue":4624,"wiki:author-members":5171},{"id":4,"title":5,"authors":6,"body":8,"chapterDepth":208,"chapterOrder":4612,"date":4613,"description":14,"docKey":4614,"docRoot":4615,"docTitle":4616,"extension":4617,"isWikiDoc":219,"isWikiIndex":4618,"meta":4619,"navigation":219,"path":4620,"seo":4621,"stem":4622,"wikiDepth":29,"__hash__":4623},"wiki\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-1600-jthread-stop-token.md","jthread 与 stop_token",[7],"董佳辉",{"type":9,"value":10,"toc":4564},"minimark",[11,15,38,46,53,61,64,70,76,79,86,93,99,126,129,145,148,162,172,188,191,314,327,333,336,342,348,355,361,364,367,369,375,378,460,463,469,474,477,489,492,495,507,510,513,519,528,531,537,540,546,555,557,563,568,575,578,584,587,593,596,599,602,608,611,614,628,631,636,638,643,645,649,655,663,668,675,678,684,686,701,704,710,715,721,724,730,732,740,743,1000,1003,1009,1012,1035,1038,1060,1063,1075,1084,1087,1093,1103,1110,1112,1117,1120,1132,1135,1143,1146,1149,1155,1158,1160,1195,1198,1211,1214,1217,1223,1226,1233,1235,1241,1249,1271,1274,1280,1283,1286,1298,1301,1303,1309,1314,1327,1330,1335,1337,1349,1352,1355,1361,1367,1373,1376,1387,1392,1394,1400,1403,1426,1429,1437,1442,1445,1451,1453,1475,1478,1499,1502,1631,1636,1642,1644,1648,1653,1701,1704,1735,1741,1747,1750,1753,1760,1763,1775,1777,1811,1814,1855,1857,1860,1863,1897,1900,1902,1914,1917,1920,1932,1935,1945,1948,1960,1963,1966,1972,1974,2008,2011,2045,2048,2050,2056,2059,2065,2068,2075,2087,2090,2097,2099,2224,2226,2232,2235,2241,2243,2254,2257,2263,2266,2285,2287,2293,2295,2302,2304,2364,2367,2370,2384,2387,2419,2422,2428,2435,2441,2443,2449,2452,2464,2467,2472,2475,2487,2489,2595,2597,2603,2605,2611,2617,2623,2626,2629,2635,2638,2644,2647,2650,2653,2656,2662,2664,2668,2676,2684,2686,2781,2783,2789,2792,2811,2816,2819,2824,2827,2833,2836,2859,2862,2875,2877,2884,2886,3041,3043,3068,3071,3087,3090,3114,3116,3166,3169,3199,3202,3208,3210,3218,3224,3257,3260,3272,3275,3289,3292,3298,3304,3306,3312,3315,3321,3324,3329,3331,3341,3346,3358,3361,3367,3373,3376,3388,3391,3397,3400,3402,3411,3414,3417,3433,3436,3448,3451,3454,3457,3469,3475,3477,3690,3693,3699,3702,3718,3721,3735,3738,3740,3754,3761,3767,3769,3772,3781,3901,3904,3910,3913,3923,3925,3934,3937,4005,4008,4028,4031,4034,4036,4042,4045,4057,4060,4063,4069,4072,4075,4081,4083,4089,4091,4097,4099,4102,4109,4112,4118,4121,4127,4129,4136,4138,4192,4198,4209,4212,4215,4226,4229,4231,4235,4237,4274,4277,4279,4288,4291,4297,4300,4302,4310,4313,4319,4322,4324,4328,4333,4340,4352,4354,4388,4395,4398,4410,4413,4415,4421,4426,4431,4434,4440,4443,4446,4449,4451,4454,4458,4467,4470,4476,4479,4485,4488,4494,4496,4502,4505,4511,4514,4532,4534,4560],[12,13,14],"p",{},"C++20 提供了：",[16,17,22],"pre",{"className":18,"code":19,"language":20,"meta":21,"style":21},"language-cpp shiki shiki-themes github-light github-dark","std::jthread\n","cpp","",[23,24,25],"code",{"__ignoreMap":21},[26,27,30,34],"span",{"class":28,"line":29},"line",1,[26,31,33],{"class":32},"sScJk","std",[26,35,37],{"class":36},"sVt8B","::jthread\n",[12,39,40,41,45],{},"它可以理解成一个",[42,43,44],"strong",{},"更适合现代 C++ 的线程类","。",[12,47,48,49,52],{},"和 ",[23,50,51],{},"std::thread"," 相比，它最重要的改进有两个：",[16,54,59],{"className":55,"code":57,"language":58,"meta":21},[56],"language-text","1. 生命周期更安全\n   → 析构时自动处理线程，不容易因为漏写 join() 而出问题\n\n2. 自带协作式停止机制\n   → 可以通过 stop_token \u002F request_stop() 请求线程安全退出\n","text",[23,60,57],{"__ignoreMap":21},[12,62,63],{},"所以这一节最重要的是把两个概念分开：",[16,65,68],{"className":66,"code":67,"language":58,"meta":21},[56],"线程生命周期管理\n→ 谁负责等待线程结束\n\n线程停止协议\n→ 谁发出停止请求，工作线程怎么响应\n",[23,69,67],{"__ignoreMap":21},[12,71,72,75],{},[23,73,74],{},"std::jthread"," 同时解决了这两个问题，但它并不是“自动强杀线程”的工具。",[77,78],"hr",{},[80,81,83,84],"h2",{"id":82},"为什么需要-stdjthread","为什么需要 ",[23,85,74],{},[87,88,90,92],"h3",{"id":89},"stdthread-的问题",[23,91,51],{}," 的问题",[12,94,95,96,98],{},"使用普通 ",[23,97,51],{},"：",[16,100,102],{"className":18,"code":101,"language":20,"meta":21,"style":21},"std::thread thread(work);\n",[23,103,104],{"__ignoreMap":21},[26,105,106,108,111,114,117,120,123],{"class":28,"line":29},[26,107,33],{"class":32},[26,109,110],{"class":36},"::",[26,112,113],{"class":32},"thread",[26,115,116],{"class":32}," thread",[26,118,119],{"class":36},"(",[26,121,122],{"class":32},"work",[26,124,125],{"class":36},");\n",[12,127,128],{},"在线程对象析构之前，必须保证它已经：",[16,130,132],{"className":18,"code":131,"language":20,"meta":21,"style":21},"thread.join();\n",[23,133,134],{"__ignoreMap":21},[26,135,136,139,142],{"class":28,"line":29},[26,137,138],{"class":36},"thread.",[26,140,141],{"class":32},"join",[26,143,144],{"class":36},"();\n",[12,146,147],{},"或者：",[16,149,151],{"className":18,"code":150,"language":20,"meta":21,"style":21},"thread.detach();\n",[23,152,153],{"__ignoreMap":21},[26,154,155,157,160],{"class":28,"line":29},[26,156,138],{"class":36},[26,158,159],{"class":32},"detach",[26,161,144],{"class":36},[12,163,164,165,168,169,171],{},"否则，如果一个仍然 ",[23,166,167],{},"joinable()"," 的 ",[23,170,51],{}," 被析构，程序会调用：",[16,173,175],{"className":18,"code":174,"language":20,"meta":21,"style":21},"std::terminate();\n",[23,176,177],{"__ignoreMap":21},[26,178,179,181,183,186],{"class":28,"line":29},[26,180,33],{"class":32},[26,182,110],{"class":36},[26,184,185],{"class":32},"terminate",[26,187,144],{"class":36},[12,189,190],{},"例如：",[16,192,194],{"className":18,"code":193,"language":20,"meta":21,"style":21},"#include \u003Cprint>\n#include \u003Cthread>\n\nvoid work()\n{\n    std::println(\"working\");\n}\n\nint main()\n{\n    std::thread thread(work);\n\n    \u002F\u002F 如果这里忘记 join() \u002F detach()\n}\n",[23,195,196,206,214,221,233,239,257,263,268,279,284,297,302,309],{"__ignoreMap":21},[26,197,198,202],{"class":28,"line":29},[26,199,201],{"class":200},"szBVR","#include",[26,203,205],{"class":204},"sZZnC"," \u003Cprint>\n",[26,207,209,211],{"class":28,"line":208},2,[26,210,201],{"class":200},[26,212,213],{"class":204}," \u003Cthread>\n",[26,215,217],{"class":28,"line":216},3,[26,218,220],{"emptyLinePlaceholder":219},true,"\n",[26,222,224,227,230],{"class":28,"line":223},4,[26,225,226],{"class":200},"void",[26,228,229],{"class":32}," work",[26,231,232],{"class":36},"()\n",[26,234,236],{"class":28,"line":235},5,[26,237,238],{"class":36},"{\n",[26,240,242,245,247,250,252,255],{"class":28,"line":241},6,[26,243,244],{"class":32},"    std",[26,246,110],{"class":36},[26,248,249],{"class":32},"println",[26,251,119],{"class":36},[26,253,254],{"class":204},"\"working\"",[26,256,125],{"class":36},[26,258,260],{"class":28,"line":259},7,[26,261,262],{"class":36},"}\n",[26,264,266],{"class":28,"line":265},8,[26,267,220],{"emptyLinePlaceholder":219},[26,269,271,274,277],{"class":28,"line":270},9,[26,272,273],{"class":200},"int",[26,275,276],{"class":32}," main",[26,278,232],{"class":36},[26,280,282],{"class":28,"line":281},10,[26,283,238],{"class":36},[26,285,287,289,292,294],{"class":28,"line":286},11,[26,288,244],{"class":32},[26,290,291],{"class":36},"::thread ",[26,293,113],{"class":32},[26,295,296],{"class":36},"(work);\n",[26,298,300],{"class":28,"line":299},12,[26,301,220],{"emptyLinePlaceholder":219},[26,303,305],{"class":28,"line":304},13,[26,306,308],{"class":307},"sJ8bj","    \u002F\u002F 如果这里忘记 join() \u002F detach()\n",[26,310,312],{"class":28,"line":311},14,[26,313,262],{"class":36},[12,315,316,317,320,321,323,324,45],{},"程序离开 ",[23,318,319],{},"main()"," 时，",[23,322,113],{}," 仍然是 joinable 的，于是会触发 ",[23,325,326],{},"std::terminate()",[12,328,329],{},[330,331],"img",{"alt":21,"src":332},"https:\u002F\u002Fcdn.tungchiahui.cn\u002Ftungwebsite\u002Fassets\u002Fimages\u002F2023\u002F10\u002F05\u002F1789303640375-2f45e713.webp",[12,334,335],{},"真正麻烦的是，当程序中出现：",[16,337,340],{"className":338,"code":339,"language":58,"meta":21},[56],"异常\n提前 return\n多个 if \u002F else 分支\n复杂资源管理\n",[23,341,339],{"__ignoreMap":21},[12,343,344,345,45],{},"就更容易漏掉 ",[23,346,347],{},"join()",[12,349,350,351,354],{},"这和手动管理 ",[23,352,353],{},"new\u002Fdelete"," 有点像：",[16,356,359],{"className":357,"code":358,"language":58,"meta":21},[56],"代码简单时看起来没问题\n\n控制路径一复杂\n→ 很容易忘记收尾\n",[23,360,358],{"__ignoreMap":21},[12,362,363],{},"而现代 C++ 更倾向于通过 RAII 自动管理资源。",[12,365,366],{},"线程也一样。",[77,368],{},[87,370,372,374],{"id":371},"stdjthread-会自动处理线程结束",[23,373,74],{}," 会自动处理线程结束",[12,376,377],{},"最简单的例子：",[16,379,381],{"className":18,"code":380,"language":20,"meta":21,"style":21},"#include \u003Cprint>\n#include \u003Cthread>\n\nvoid work()\n{\n    std::println(\"working\");\n}\n\nint main()\n{\n    std::jthread thread(work);\n}\n",[23,382,383,389,395,399,407,411,425,429,433,441,445,456],{"__ignoreMap":21},[26,384,385,387],{"class":28,"line":29},[26,386,201],{"class":200},[26,388,205],{"class":204},[26,390,391,393],{"class":28,"line":208},[26,392,201],{"class":200},[26,394,213],{"class":204},[26,396,397],{"class":28,"line":216},[26,398,220],{"emptyLinePlaceholder":219},[26,400,401,403,405],{"class":28,"line":223},[26,402,226],{"class":200},[26,404,229],{"class":32},[26,406,232],{"class":36},[26,408,409],{"class":28,"line":235},[26,410,238],{"class":36},[26,412,413,415,417,419,421,423],{"class":28,"line":241},[26,414,244],{"class":32},[26,416,110],{"class":36},[26,418,249],{"class":32},[26,420,119],{"class":36},[26,422,254],{"class":204},[26,424,125],{"class":36},[26,426,427],{"class":28,"line":259},[26,428,262],{"class":36},[26,430,431],{"class":28,"line":265},[26,432,220],{"emptyLinePlaceholder":219},[26,434,435,437,439],{"class":28,"line":270},[26,436,273],{"class":200},[26,438,276],{"class":32},[26,440,232],{"class":36},[26,442,443],{"class":28,"line":281},[26,444,238],{"class":36},[26,446,447,449,452,454],{"class":28,"line":286},[26,448,244],{"class":32},[26,450,451],{"class":36},"::jthread ",[26,453,113],{"class":32},[26,455,296],{"class":36},[26,457,458],{"class":28,"line":299},[26,459,262],{"class":36},[12,461,462],{},"运行结果：",[16,464,467],{"className":465,"code":466,"language":58,"meta":21},[56],"working\n",[23,468,466],{"__ignoreMap":21},[12,470,471],{},[330,472],{"alt":21,"src":473},"https:\u002F\u002Fcdn.tungchiahui.cn\u002Ftungwebsite\u002Fassets\u002Fimages\u002F2023\u002F10\u002F05\u002F1789303670123-6fc66656.webp",[12,475,476],{},"这里没有写：",[16,478,479],{"className":18,"code":131,"language":20,"meta":21,"style":21},[23,480,481],{"__ignoreMap":21},[26,482,483,485,487],{"class":28,"line":29},[26,484,138],{"class":36},[26,486,141],{"class":32},[26,488,144],{"class":36},[12,490,491],{},"但程序仍然可以正常结束。",[12,493,494],{},"因为当：",[16,496,498],{"className":18,"code":497,"language":20,"meta":21,"style":21},"std::jthread thread;\n",[23,499,500],{"__ignoreMap":21},[26,501,502,504],{"class":28,"line":29},[26,503,33],{"class":32},[26,505,506],{"class":36},"::jthread thread;\n",[12,508,509],{},"离开作用域时，如果它仍然是 joinable 的，析构函数会负责收尾。",[12,511,512],{},"可以先粗略理解成：",[16,514,517],{"className":515,"code":516,"language":58,"meta":21},[56],"std::thread\n→ 需要自己保证 join() \u002F detach()\n\nstd::jthread\n→ 析构时自动处理\n",[23,518,516],{"__ignoreMap":21},[12,520,521,522,525,526,45],{},"不过 ",[23,523,524],{},"jthread"," 的析构不只是简单地 ",[23,527,347],{},[12,529,530],{},"更准确地说，如果它仍然 joinable，析构过程概念上会做：",[16,532,535],{"className":533,"code":534,"language":58,"meta":21},[56],"request_stop()\n      ↓\njoin()\n",[23,536,534],{"__ignoreMap":21},[12,538,539],{},"也就是：",[541,542,543],"blockquote",{},[12,544,545],{},"先请求线程停止，然后等待线程真正结束。",[12,547,548,549,551,552,554],{},"这也是 ",[23,550,524],{}," 和普通 ",[23,553,113],{}," 一个很重要的区别。",[77,556],{},[87,558,560,562],{"id":559},"jthread-不会强制杀死线程",[23,561,524],{}," 不会强制杀死线程",[12,564,565,567],{},[23,566,74],{}," 使用的是：",[541,569,570],{},[12,571,572],{},[42,573,574],{},"协作式停止（cooperative cancellation）",[12,576,577],{},"所谓“协作式”，意思是：",[16,579,582],{"className":580,"code":581,"language":58,"meta":21},[56],"某个线程：\n发出停止请求\n      ↓\n工作线程：\n看到停止请求\n      ↓\n工作线程：\n自己选择一个安全的位置退出\n",[23,583,581],{"__ignoreMap":21},[12,585,586],{},"而不是：",[16,588,591],{"className":589,"code":590,"language":58,"meta":21},[56],"request_stop()\n      ↓\n操作系统立刻把工作线程强行杀掉\n",[23,592,590],{"__ignoreMap":21},[12,594,595],{},"标准库不会随便把线程从某条机器指令中间直接掐死。",[12,597,598],{},"原因很简单。",[12,600,601],{},"线程可能正在：",[16,603,606],{"className":604,"code":605,"language":58,"meta":21},[56],"持有 mutex\n修改共享数据\n写文件\n操作硬件\n分配 \u002F 释放资源\n修改对象内部状态\n",[23,607,605],{"__ignoreMap":21},[12,609,610],{},"如果在任意位置强制终止线程，很容易把程序状态搞坏。",[12,612,613],{},"所以：",[16,615,617],{"className":18,"code":616,"language":20,"meta":21,"style":21},"thread.request_stop();\n",[23,618,619],{"__ignoreMap":21},[26,620,621,623,626],{"class":28,"line":29},[26,622,138],{"class":36},[26,624,625],{"class":32},"request_stop",[26,627,144],{"class":36},[12,629,630],{},"更像是在告诉工作线程：",[541,632,633],{},[12,634,635],{},"“你该停了，请在合适的位置自己退出。”",[12,637,586],{},[541,639,640],{},[12,641,642],{},"“现在立刻把你杀掉。”",[77,644],{},[80,646,648],{"id":647},"stop_token-停止协议","stop_token 停止协议",[87,650,652],{"id":651},"stdstop_token",[23,653,654],{},"std::stop_token",[656,657,659,662],"h4",{"id":658},"stop_token-是什么",[23,660,661],{},"stop_token"," 是什么",[12,664,665,667],{},[23,666,654],{}," 可以理解成：",[541,669,670],{},[12,671,672],{},[42,673,674],{},"停止请求的观察端。",[12,676,677],{},"它本身不能发出停止请求，只能查看：",[16,679,682],{"className":680,"code":681,"language":58,"meta":21},[56],"有没有人要求我停止？\n",[23,683,681],{"__ignoreMap":21},[12,685,190],{},[16,687,689],{"className":18,"code":688,"language":20,"meta":21,"style":21},"stop_token.stop_requested();\n",[23,690,691],{"__ignoreMap":21},[26,692,693,696,699],{"class":28,"line":29},[26,694,695],{"class":36},"stop_token.",[26,697,698],{"class":32},"stop_requested",[26,700,144],{"class":36},[12,702,703],{},"返回：",[16,705,708],{"className":706,"code":707,"language":58,"meta":21},[56],"true  → 已经有人请求停止\nfalse → 目前还没有停止请求\n",[23,709,707],{"__ignoreMap":21},[12,711,712,714],{},[23,713,524],{}," 内部有一个停止状态，可以粗略理解成：",[16,716,719],{"className":717,"code":718,"language":58,"meta":21},[56],"jthread \u002F stop_source\n        ↓\n   发出停止请求\n\n   共享停止状态\n\n        ↑\n   查看停止请求\n        ↑\n    stop_token\n",[23,720,718],{"__ignoreMap":21},[12,722,723],{},"也就是说：",[16,725,728],{"className":726,"code":727,"language":58,"meta":21},[56],"request_stop()\n→ 写入“停止请求”\n\nstop_requested()\n→ 查看“停止请求”\n",[23,729,727],{"__ignoreMap":21},[77,731],{},[87,733,735,737,738],{"id":734},"jthread-可以自动传入-stop_token",[23,736,524],{}," 可以自动传入 ",[23,739,661],{},[12,741,742],{},"来看一个最典型的例子：",[16,744,746],{"className":18,"code":745,"language":20,"meta":21,"style":21},"#include \u003Cchrono>\n#include \u003Cprint>\n#include \u003Cstop_token>\n#include \u003Cthread>\n\nusing namespace std::chrono_literals;\n\nvoid worker(std::stop_token token)\n{\n    while (!token.stop_requested())\n    {\n        std::println(\"working\");\n        std::this_thread::sleep_for(100ms);\n    }\n\n    std::println(\"stopping\");\n}\n\nint main()\n{\n    std::jthread thread(worker);\n\n    std::this_thread::sleep_for(350ms);\n\n    thread.request_stop();\n}\n",[23,747,748,755,761,768,774,778,797,801,823,827,846,851,866,891,896,901,917,922,927,936,941,953,958,980,985,995],{"__ignoreMap":21},[26,749,750,752],{"class":28,"line":29},[26,751,201],{"class":200},[26,753,754],{"class":204}," \u003Cchrono>\n",[26,756,757,759],{"class":28,"line":208},[26,758,201],{"class":200},[26,760,205],{"class":204},[26,762,763,765],{"class":28,"line":216},[26,764,201],{"class":200},[26,766,767],{"class":204}," \u003Cstop_token>\n",[26,769,770,772],{"class":28,"line":223},[26,771,201],{"class":200},[26,773,213],{"class":204},[26,775,776],{"class":28,"line":235},[26,777,220],{"emptyLinePlaceholder":219},[26,779,780,783,786,789,791,794],{"class":28,"line":241},[26,781,782],{"class":200},"using",[26,784,785],{"class":200}," namespace",[26,787,788],{"class":32}," std",[26,790,110],{"class":36},[26,792,793],{"class":32},"chrono_literals",[26,795,796],{"class":36},";\n",[26,798,799],{"class":28,"line":259},[26,800,220],{"emptyLinePlaceholder":219},[26,802,803,805,808,810,812,814,816,820],{"class":28,"line":265},[26,804,226],{"class":200},[26,806,807],{"class":32}," worker",[26,809,119],{"class":36},[26,811,33],{"class":32},[26,813,110],{"class":36},[26,815,661],{"class":32},[26,817,819],{"class":818},"s4XuR"," token",[26,821,822],{"class":36},")\n",[26,824,825],{"class":28,"line":270},[26,826,238],{"class":36},[26,828,829,832,835,838,841,843],{"class":28,"line":281},[26,830,831],{"class":200},"    while",[26,833,834],{"class":36}," (",[26,836,837],{"class":200},"!",[26,839,840],{"class":36},"token.",[26,842,698],{"class":32},[26,844,845],{"class":36},"())\n",[26,847,848],{"class":28,"line":286},[26,849,850],{"class":36},"    {\n",[26,852,853,856,858,860,862,864],{"class":28,"line":299},[26,854,855],{"class":32},"        std",[26,857,110],{"class":36},[26,859,249],{"class":32},[26,861,119],{"class":36},[26,863,254],{"class":204},[26,865,125],{"class":36},[26,867,868,870,872,875,877,880,882,886,889],{"class":28,"line":304},[26,869,855],{"class":32},[26,871,110],{"class":36},[26,873,874],{"class":32},"this_thread",[26,876,110],{"class":36},[26,878,879],{"class":32},"sleep_for",[26,881,119],{"class":36},[26,883,885],{"class":884},"sj4cs","100",[26,887,888],{"class":200},"ms",[26,890,125],{"class":36},[26,892,893],{"class":28,"line":311},[26,894,895],{"class":36},"    }\n",[26,897,899],{"class":28,"line":898},15,[26,900,220],{"emptyLinePlaceholder":219},[26,902,904,906,908,910,912,915],{"class":28,"line":903},16,[26,905,244],{"class":32},[26,907,110],{"class":36},[26,909,249],{"class":32},[26,911,119],{"class":36},[26,913,914],{"class":204},"\"stopping\"",[26,916,125],{"class":36},[26,918,920],{"class":28,"line":919},17,[26,921,262],{"class":36},[26,923,925],{"class":28,"line":924},18,[26,926,220],{"emptyLinePlaceholder":219},[26,928,930,932,934],{"class":28,"line":929},19,[26,931,273],{"class":200},[26,933,276],{"class":32},[26,935,232],{"class":36},[26,937,939],{"class":28,"line":938},20,[26,940,238],{"class":36},[26,942,944,946,948,950],{"class":28,"line":943},21,[26,945,244],{"class":32},[26,947,451],{"class":36},[26,949,113],{"class":32},[26,951,952],{"class":36},"(worker);\n",[26,954,956],{"class":28,"line":955},22,[26,957,220],{"emptyLinePlaceholder":219},[26,959,961,963,965,967,969,971,973,976,978],{"class":28,"line":960},23,[26,962,244],{"class":32},[26,964,110],{"class":36},[26,966,874],{"class":32},[26,968,110],{"class":36},[26,970,879],{"class":32},[26,972,119],{"class":36},[26,974,975],{"class":884},"350",[26,977,888],{"class":200},[26,979,125],{"class":36},[26,981,983],{"class":28,"line":982},24,[26,984,220],{"emptyLinePlaceholder":219},[26,986,988,991,993],{"class":28,"line":987},25,[26,989,990],{"class":36},"    thread.",[26,992,625],{"class":32},[26,994,144],{"class":36},[26,996,998],{"class":28,"line":997},26,[26,999,262],{"class":36},[12,1001,1002],{},"可能输出：",[16,1004,1007],{"className":1005,"code":1006,"language":58,"meta":21},[56],"working\nworking\nworking\nworking\nstopping\n",[23,1008,1006],{"__ignoreMap":21},[12,1010,1011],{},"这里最特别的是：",[16,1013,1015],{"className":18,"code":1014,"language":20,"meta":21,"style":21},"void worker(std::stop_token token)\n",[23,1016,1017],{"__ignoreMap":21},[26,1018,1019,1021,1023,1025,1027,1029,1031,1033],{"class":28,"line":29},[26,1020,226],{"class":200},[26,1022,807],{"class":32},[26,1024,119],{"class":36},[26,1026,33],{"class":32},[26,1028,110],{"class":36},[26,1030,661],{"class":32},[26,1032,819],{"class":818},[26,1034,822],{"class":36},[12,1036,1037],{},"但创建线程时却只写了：",[16,1039,1041],{"className":18,"code":1040,"language":20,"meta":21,"style":21},"std::jthread thread(worker);\n",[23,1042,1043],{"__ignoreMap":21},[26,1044,1045,1047,1049,1051,1053,1055,1058],{"class":28,"line":29},[26,1046,33],{"class":32},[26,1048,110],{"class":36},[26,1050,524],{"class":32},[26,1052,116],{"class":32},[26,1054,119],{"class":36},[26,1056,1057],{"class":32},"worker",[26,1059,125],{"class":36},[12,1061,1062],{},"我们并没有手动传：",[16,1064,1066],{"className":18,"code":1065,"language":20,"meta":21,"style":21},"worker(token);\n",[23,1067,1068],{"__ignoreMap":21},[26,1069,1070,1072],{"class":28,"line":29},[26,1071,1057],{"class":32},[26,1073,1074],{"class":36},"(token);\n",[12,1076,1077,1078,1080,1081,1083],{},"因为 ",[23,1079,74],{}," 发现这个函数可以接收 ",[23,1082,654],{},"，于是会自动把自己的 stop token 传进去。",[12,1085,1086],{},"可以近似理解成：",[16,1088,1091],{"className":1089,"code":1090,"language":58,"meta":21},[56],"std::jthread thread(worker);\n\n内部效果类似：\n\nworker(jthread 自动提供的 stop_token);\n",[23,1092,1090],{"__ignoreMap":21},[12,1094,1095,1096,1099,1100,45],{},"这里不可以显式填参数，比如",[23,1097,1098],{},"std::jthread thread(worker, thread.get_stop_token());","，\n这是非法的，原因非常直接：在执行构造函数参数时，thread 对象还没有构造完成，所以你还不能调用",[23,1101,1102],{},"thread.get_stop_token()",[12,1104,1105,1106,1109],{},"所以这里直接记住他会自动把自己的",[23,1107,1108],{},"stop token","传入进去就行了，不需要我们手动传入。",[77,1111],{},[87,1113,1114],{"id":625},[23,1115,1116],{},"request_stop()",[12,1118,1119],{},"调用：",[16,1121,1122],{"className":18,"code":616,"language":20,"meta":21,"style":21},[23,1123,1124],{"__ignoreMap":21},[26,1125,1126,1128,1130],{"class":28,"line":29},[26,1127,138],{"class":36},[26,1129,625],{"class":32},[26,1131,144],{"class":36},[12,1133,1134],{},"表示：",[541,1136,1137],{},[12,1138,1139,1140,1142],{},"向这个 ",[23,1141,524],{}," 关联的停止状态发出停止请求。",[12,1144,1145],{},"它只负责“发请求”。",[12,1147,1148],{},"它不会：",[16,1150,1153],{"className":1151,"code":1152,"language":58,"meta":21},[56],"强制终止线程\n自动跳出 while\n直接让 worker return\n等待线程结束\n",[23,1154,1152],{"__ignoreMap":21},[12,1156,1157],{},"真正决定什么时候退出的是工作线程。",[12,1159,190],{},[16,1161,1163],{"className":18,"code":1162,"language":20,"meta":21,"style":21},"while (!token.stop_requested())\n{\n    do_work();\n}\n",[23,1164,1165,1180,1184,1191],{"__ignoreMap":21},[26,1166,1167,1170,1172,1174,1176,1178],{"class":28,"line":29},[26,1168,1169],{"class":200},"while",[26,1171,834],{"class":36},[26,1173,837],{"class":200},[26,1175,840],{"class":36},[26,1177,698],{"class":32},[26,1179,845],{"class":36},[26,1181,1182],{"class":28,"line":208},[26,1183,238],{"class":36},[26,1185,1186,1189],{"class":28,"line":216},[26,1187,1188],{"class":32},"    do_work",[26,1190,144],{"class":36},[26,1192,1193],{"class":28,"line":223},[26,1194,262],{"class":36},[12,1196,1197],{},"每轮循环检查：",[16,1199,1201],{"className":18,"code":1200,"language":20,"meta":21,"style":21},"token.stop_requested()\n",[23,1202,1203],{"__ignoreMap":21},[26,1204,1205,1207,1209],{"class":28,"line":29},[26,1206,840],{"class":36},[26,1208,698],{"class":32},[26,1210,232],{"class":36},[12,1212,1213],{},"一旦发现停止请求，就退出循环。",[12,1215,1216],{},"整个流程是：",[16,1218,1221],{"className":1219,"code":1220,"language":58,"meta":21},[56],"main\n│\n│ 创建 jthread\n↓\nworker 开始执行\n│\n│ while (!token.stop_requested())\n│\n│ working...\n│\n│ working...\n│\n↑\nmain 调用 request_stop()\n│\n↓\n停止状态变成“已请求停止”\n│\n↓\nworker 下一次检查 stop_requested()\n│\n↓\n发现为 true\n│\n↓\n退出循环\n",[23,1222,1220],{"__ignoreMap":21},[12,1224,1225],{},"所以最重要的一句话是：",[541,1227,1228],{},[12,1229,1230,1232],{},[23,1231,1116],{}," 只是请求停止，真正停止必须由工作线程自己配合。",[77,1234],{},[87,1236,1238,1240],{"id":1237},"request_stop-的返回值",[23,1239,1116],{}," 的返回值",[12,1242,1243,1245,1246,98],{},[23,1244,1116],{}," 会返回一个 ",[23,1247,1248],{},"bool",[16,1250,1252],{"className":18,"code":1251,"language":20,"meta":21,"style":21},"bool result = thread.request_stop();\n",[23,1253,1254],{"__ignoreMap":21},[26,1255,1256,1258,1261,1264,1267,1269],{"class":28,"line":29},[26,1257,1248],{"class":200},[26,1259,1260],{"class":36}," result ",[26,1262,1263],{"class":200},"=",[26,1265,1266],{"class":36}," thread.",[26,1268,625],{"class":32},[26,1270,144],{"class":36},[12,1272,1273],{},"可以粗略理解成：",[16,1275,1278],{"className":1276,"code":1277,"language":58,"meta":21},[56],"true\n→ 这次调用真的把状态从\n  “还没请求停止”\n  改成了\n  “已经请求停止”\n\nfalse\n→ 之前已经请求过停止\n  或者当前停止状态无法产生停止请求\n",[23,1279,1277],{"__ignoreMap":21},[12,1281,1282],{},"普通业务代码经常不需要关心这个返回值。",[12,1284,1285],{},"直接写：",[16,1287,1288],{"className":18,"code":616,"language":20,"meta":21,"style":21},[23,1289,1290],{"__ignoreMap":21},[26,1291,1292,1294,1296],{"class":28,"line":29},[26,1293,138],{"class":36},[26,1295,625],{"class":32},[26,1297,144],{"class":36},[12,1299,1300],{},"就可以。",[77,1302],{},[87,1304,1306],{"id":1305},"stop_possible",[23,1307,1308],{},"stop_possible()",[12,1310,1311,1313],{},[23,1312,661],{}," 还可以调用：",[16,1315,1317],{"className":18,"code":1316,"language":20,"meta":21,"style":21},"token.stop_possible();\n",[23,1318,1319],{"__ignoreMap":21},[26,1320,1321,1323,1325],{"class":28,"line":29},[26,1322,840],{"class":36},[26,1324,1305],{"class":32},[26,1326,144],{"class":36},[12,1328,1329],{},"它表示：",[541,1331,1332],{},[12,1333,1334],{},"这个 token 是否关联着一个“有可能收到停止请求”的停止状态。",[12,1336,190],{},[16,1338,1340],{"className":18,"code":1339,"language":20,"meta":21,"style":21},"std::stop_token token;\n",[23,1341,1342],{"__ignoreMap":21},[26,1343,1344,1346],{"class":28,"line":29},[26,1345,33],{"class":32},[26,1347,1348],{"class":36},"::stop_token token;\n",[12,1350,1351],{},"这是一个默认构造的 token，它没有关联正常的停止状态。",[12,1353,1354],{},"此时通常：",[16,1356,1359],{"className":1357,"code":1358,"language":58,"meta":21},[56],"token.stop_possible()  == false\ntoken.stop_requested() == false\n",[23,1360,1358],{"__ignoreMap":21},[12,1362,1363,1364,1366],{},"而 ",[23,1365,74],{}," 自动提供的 token 通常是：",[16,1368,1371],{"className":1369,"code":1370,"language":58,"meta":21},[56],"stop_possible() == true\n",[23,1372,1370],{"__ignoreMap":21},[12,1374,1375],{},"对于普通使用来说，最常用的还是：",[16,1377,1379],{"className":18,"code":1378,"language":20,"meta":21,"style":21},"stop_requested()\n",[23,1380,1381],{"__ignoreMap":21},[26,1382,1383,1385],{"class":28,"line":29},[26,1384,698],{"class":32},[26,1386,232],{"class":36},[12,1388,1389,1391],{},[23,1390,1308],{}," 更多是在需要判断“这个 token 到底支不支持停止协议”时使用。",[77,1393],{},[87,1395,1397,1399],{"id":1396},"jthread-析构时到底发生什么",[23,1398,524],{}," 析构时到底发生什么",[12,1401,1402],{},"假设：",[16,1404,1406],{"className":18,"code":1405,"language":20,"meta":21,"style":21},"{\n    std::jthread thread(worker);\n}\n",[23,1407,1408,1412,1422],{"__ignoreMap":21},[26,1409,1410],{"class":28,"line":29},[26,1411,238],{"class":36},[26,1413,1414,1416,1418,1420],{"class":28,"line":208},[26,1415,244],{"class":32},[26,1417,451],{"class":36},[26,1419,113],{"class":32},[26,1421,952],{"class":36},[26,1423,1424],{"class":28,"line":216},[26,1425,262],{"class":36},[12,1427,1428],{},"执行到右花括号：",[16,1430,1431],{"className":18,"code":262,"language":20,"meta":21,"style":21},[23,1432,1433],{"__ignoreMap":21},[26,1434,1435],{"class":28,"line":29},[26,1436,262],{"class":36},[12,1438,1439,1441],{},[23,1440,113],{}," 开始析构。",[12,1443,1444],{},"如果它仍然是 joinable 的，那么概念上会：",[16,1446,1449],{"className":1447,"code":1448,"language":58,"meta":21},[56],"thread.request_stop();\n        ↓\nthread.join();\n",[23,1450,1448],{"__ignoreMap":21},[12,1452,613],{},[16,1454,1455],{"className":18,"code":1405,"language":20,"meta":21,"style":21},[23,1456,1457,1461,1471],{"__ignoreMap":21},[26,1458,1459],{"class":28,"line":29},[26,1460,238],{"class":36},[26,1462,1463,1465,1467,1469],{"class":28,"line":208},[26,1464,244],{"class":32},[26,1466,451],{"class":36},[26,1468,113],{"class":32},[26,1470,952],{"class":36},[26,1472,1473],{"class":28,"line":216},[26,1474,262],{"class":36},[12,1476,1477],{},"可以理解成退出作用域时自动做了：",[16,1479,1481],{"className":18,"code":1480,"language":20,"meta":21,"style":21},"thread.request_stop();\nthread.join();\n",[23,1482,1483,1491],{"__ignoreMap":21},[26,1484,1485,1487,1489],{"class":28,"line":29},[26,1486,138],{"class":36},[26,1488,625],{"class":32},[26,1490,144],{"class":36},[26,1492,1493,1495,1497],{"class":28,"line":208},[26,1494,138],{"class":36},[26,1496,141],{"class":32},[26,1498,144],{"class":36},[12,1500,1501],{},"这也是为什么这种代码可以正常工作：",[16,1503,1505],{"className":18,"code":1504,"language":20,"meta":21,"style":21},"#include \u003Cprint>\n#include \u003Cstop_token>\n#include \u003Cthread>\n\nvoid worker(std::stop_token token)\n{\n    while (!token.stop_requested())\n    {\n        \u002F\u002F work\n    }\n\n    std::println(\"stopped\");\n}\n\nint main()\n{\n    std::jthread thread(worker);\n}\n",[23,1506,1507,1513,1519,1525,1529,1547,1551,1565,1569,1574,1578,1582,1597,1601,1605,1613,1617,1627],{"__ignoreMap":21},[26,1508,1509,1511],{"class":28,"line":29},[26,1510,201],{"class":200},[26,1512,205],{"class":204},[26,1514,1515,1517],{"class":28,"line":208},[26,1516,201],{"class":200},[26,1518,767],{"class":204},[26,1520,1521,1523],{"class":28,"line":216},[26,1522,201],{"class":200},[26,1524,213],{"class":204},[26,1526,1527],{"class":28,"line":223},[26,1528,220],{"emptyLinePlaceholder":219},[26,1530,1531,1533,1535,1537,1539,1541,1543,1545],{"class":28,"line":235},[26,1532,226],{"class":200},[26,1534,807],{"class":32},[26,1536,119],{"class":36},[26,1538,33],{"class":32},[26,1540,110],{"class":36},[26,1542,661],{"class":32},[26,1544,819],{"class":818},[26,1546,822],{"class":36},[26,1548,1549],{"class":28,"line":241},[26,1550,238],{"class":36},[26,1552,1553,1555,1557,1559,1561,1563],{"class":28,"line":259},[26,1554,831],{"class":200},[26,1556,834],{"class":36},[26,1558,837],{"class":200},[26,1560,840],{"class":36},[26,1562,698],{"class":32},[26,1564,845],{"class":36},[26,1566,1567],{"class":28,"line":265},[26,1568,850],{"class":36},[26,1570,1571],{"class":28,"line":270},[26,1572,1573],{"class":307},"        \u002F\u002F work\n",[26,1575,1576],{"class":28,"line":281},[26,1577,895],{"class":36},[26,1579,1580],{"class":28,"line":286},[26,1581,220],{"emptyLinePlaceholder":219},[26,1583,1584,1586,1588,1590,1592,1595],{"class":28,"line":299},[26,1585,244],{"class":32},[26,1587,110],{"class":36},[26,1589,249],{"class":32},[26,1591,119],{"class":36},[26,1593,1594],{"class":204},"\"stopped\"",[26,1596,125],{"class":36},[26,1598,1599],{"class":28,"line":304},[26,1600,262],{"class":36},[26,1602,1603],{"class":28,"line":311},[26,1604,220],{"emptyLinePlaceholder":219},[26,1606,1607,1609,1611],{"class":28,"line":898},[26,1608,273],{"class":200},[26,1610,276],{"class":32},[26,1612,232],{"class":36},[26,1614,1615],{"class":28,"line":903},[26,1616,238],{"class":36},[26,1618,1619,1621,1623,1625],{"class":28,"line":919},[26,1620,244],{"class":32},[26,1622,451],{"class":36},[26,1624,113],{"class":32},[26,1626,952],{"class":36},[26,1628,1629],{"class":28,"line":924},[26,1630,262],{"class":36},[12,1632,1633,1635],{},[23,1634,319],{}," 结束时：",[16,1637,1640],{"className":1638,"code":1639,"language":58,"meta":21},[56],"jthread 析构\n    ↓\nrequest_stop()\n    ↓\nworker 看到停止请求\n    ↓\nworker 退出\n    ↓\njoin() 等待结束\n    ↓\n析构完成\n",[23,1641,1639],{"__ignoreMap":21},[77,1643],{},[87,1645,1647],{"id":1646},"但析构也不能凭空让线程退出","但析构也不能“凭空让线程退出”",[12,1649,1650,1651,98],{},"下面这个线程完全不检查 ",[23,1652,661],{},[16,1654,1656],{"className":18,"code":1655,"language":20,"meta":21,"style":21},"void worker(std::stop_token)\n{\n    for (;;)   \u002F\u002F死循环，效率比while(true)高\n    {\n    }\n}\n",[23,1657,1658,1674,1678,1689,1693,1697],{"__ignoreMap":21},[26,1659,1660,1662,1664,1666,1668,1670,1672],{"class":28,"line":29},[26,1661,226],{"class":200},[26,1663,807],{"class":32},[26,1665,119],{"class":36},[26,1667,33],{"class":32},[26,1669,110],{"class":36},[26,1671,661],{"class":32},[26,1673,822],{"class":36},[26,1675,1676],{"class":28,"line":208},[26,1677,238],{"class":36},[26,1679,1680,1683,1686],{"class":28,"line":216},[26,1681,1682],{"class":200},"    for",[26,1684,1685],{"class":36}," (;;)",[26,1687,1688],{"class":307},"   \u002F\u002F死循环，效率比while(true)高\n",[26,1690,1691],{"class":28,"line":223},[26,1692,850],{"class":36},[26,1694,1695],{"class":28,"line":235},[26,1696,895],{"class":36},[26,1698,1699],{"class":28,"line":241},[26,1700,262],{"class":36},[12,1702,1703],{},"然后：",[16,1705,1707],{"className":18,"code":1706,"language":20,"meta":21,"style":21},"int main()\n{\n    std::jthread thread(worker);\n}\n",[23,1708,1709,1717,1721,1731],{"__ignoreMap":21},[26,1710,1711,1713,1715],{"class":28,"line":29},[26,1712,273],{"class":200},[26,1714,276],{"class":32},[26,1716,232],{"class":36},[26,1718,1719],{"class":28,"line":208},[26,1720,238],{"class":36},[26,1722,1723,1725,1727,1729],{"class":28,"line":216},[26,1724,244],{"class":32},[26,1726,451],{"class":36},[26,1728,113],{"class":32},[26,1730,952],{"class":36},[26,1732,1733],{"class":28,"line":223},[26,1734,262],{"class":36},[12,1736,1737,1738,1740],{},"离开 ",[23,1739,319],{}," 时：",[16,1742,1745],{"className":1743,"code":1744,"language":58,"meta":21},[56],"jthread 析构\n    ↓\nrequest_stop()\n    ↓\n停止请求确实发出了\n    ↓\n但是 worker 根本不检查\n    ↓\nfor(;;) 继续运行\n    ↓\n析构函数接着 join()\n    ↓\njoin() 一直等\n",[23,1746,1744],{"__ignoreMap":21},[12,1748,1749],{},"程序就会一直卡在那里。",[12,1751,1752],{},"因此：",[541,1754,1755],{},[12,1756,1757,1759],{},[23,1758,524],{}," 提供的是停止协议，不是强制终止能力。",[12,1761,1762],{},"所以对于长期运行的 worker，一般应该在合适的位置检查：",[16,1764,1765],{"className":18,"code":1200,"language":20,"meta":21,"style":21},[23,1766,1767],{"__ignoreMap":21},[26,1768,1769,1771,1773],{"class":28,"line":29},[26,1770,840],{"class":36},[26,1772,698],{"class":32},[26,1774,232],{"class":36},[12,1776,190],{},[16,1778,1780],{"className":18,"code":1779,"language":20,"meta":21,"style":21},"while (!token.stop_requested())\n{\n    do_some_work();\n}\n",[23,1781,1782,1796,1800,1807],{"__ignoreMap":21},[26,1783,1784,1786,1788,1790,1792,1794],{"class":28,"line":29},[26,1785,1169],{"class":200},[26,1787,834],{"class":36},[26,1789,837],{"class":200},[26,1791,840],{"class":36},[26,1793,698],{"class":32},[26,1795,845],{"class":36},[26,1797,1798],{"class":28,"line":208},[26,1799,238],{"class":36},[26,1801,1802,1805],{"class":28,"line":216},[26,1803,1804],{"class":32},"    do_some_work",[26,1806,144],{"class":36},[26,1808,1809],{"class":28,"line":223},[26,1810,262],{"class":36},[12,1812,1813],{},"而不是只在线程开头检查一次：",[16,1815,1817],{"className":18,"code":1816,"language":20,"meta":21,"style":21},"if (token.stop_requested())\n{\n    return;\n}\n\n\u002F\u002F 后面运行几个小时都不再检查\n",[23,1818,1819,1831,1835,1842,1846,1850],{"__ignoreMap":21},[26,1820,1821,1824,1827,1829],{"class":28,"line":29},[26,1822,1823],{"class":200},"if",[26,1825,1826],{"class":36}," (token.",[26,1828,698],{"class":32},[26,1830,845],{"class":36},[26,1832,1833],{"class":28,"line":208},[26,1834,238],{"class":36},[26,1836,1837,1840],{"class":28,"line":216},[26,1838,1839],{"class":200},"    return",[26,1841,796],{"class":36},[26,1843,1844],{"class":28,"line":223},[26,1845,262],{"class":36},[26,1847,1848],{"class":28,"line":235},[26,1849,220],{"emptyLinePlaceholder":219},[26,1851,1852],{"class":28,"line":241},[26,1853,1854],{"class":307},"\u002F\u002F 后面运行几个小时都不再检查\n",[77,1856],{},[87,1858,1859],{"id":1859},"阻塞操作也会影响停止速度",[12,1861,1862],{},"即使代码写成：",[16,1864,1866],{"className":18,"code":1865,"language":20,"meta":21,"style":21},"while (!token.stop_requested())\n{\n    blocking_operation();\n}\n",[23,1867,1868,1882,1886,1893],{"__ignoreMap":21},[26,1869,1870,1872,1874,1876,1878,1880],{"class":28,"line":29},[26,1871,1169],{"class":200},[26,1873,834],{"class":36},[26,1875,837],{"class":200},[26,1877,840],{"class":36},[26,1879,698],{"class":32},[26,1881,845],{"class":36},[26,1883,1884],{"class":28,"line":208},[26,1885,238],{"class":36},[26,1887,1888,1891],{"class":28,"line":216},[26,1889,1890],{"class":32},"    blocking_operation",[26,1892,144],{"class":36},[26,1894,1895],{"class":28,"line":223},[26,1896,262],{"class":36},[12,1898,1899],{},"也不代表线程一定能马上停止。",[12,1901,1402],{},[16,1903,1905],{"className":18,"code":1904,"language":20,"meta":21,"style":21},"blocking_operation();\n",[23,1906,1907],{"__ignoreMap":21},[26,1908,1909,1912],{"class":28,"line":29},[26,1910,1911],{"class":32},"blocking_operation",[26,1913,144],{"class":36},[12,1915,1916],{},"一次会阻塞 30 秒。",[12,1918,1919],{},"那么即使外部已经执行：",[16,1921,1922],{"className":18,"code":616,"language":20,"meta":21,"style":21},[23,1923,1924],{"__ignoreMap":21},[26,1925,1926,1928,1930],{"class":28,"line":29},[26,1927,138],{"class":36},[26,1929,625],{"class":32},[26,1931,144],{"class":36},[12,1933,1934],{},"工作线程也必须先从：",[16,1936,1937],{"className":18,"code":1904,"language":20,"meta":21,"style":21},[23,1938,1939],{"__ignoreMap":21},[26,1940,1941,1943],{"class":28,"line":29},[26,1942,1911],{"class":32},[26,1944,144],{"class":36},[12,1946,1947],{},"返回，才能进行下一轮：",[16,1949,1950],{"className":18,"code":1200,"language":20,"meta":21,"style":21},[23,1951,1952],{"__ignoreMap":21},[26,1953,1954,1956,1958],{"class":28,"line":29},[26,1955,840],{"class":36},[26,1957,698],{"class":32},[26,1959,232],{"class":36},[12,1961,1962],{},"所以停止响应速度还取决于工作线程内部在干什么。",[12,1964,1965],{},"对于需要快速停止的线程，要考虑：",[16,1967,1970],{"className":1968,"code":1969,"language":58,"meta":21},[56],"阻塞函数有没有超时\n\n阻塞操作能不能被唤醒\n\n能不能把长任务拆成多个小步骤\n\n能不能在多个安全点检查 stop_requested()\n",[23,1971,1969],{"__ignoreMap":21},[12,1973,190],{},[16,1975,1977],{"className":18,"code":1976,"language":20,"meta":21,"style":21},"while (!token.stop_requested())\n{\n    do_small_step();\n}\n",[23,1978,1979,1993,1997,2004],{"__ignoreMap":21},[26,1980,1981,1983,1985,1987,1989,1991],{"class":28,"line":29},[26,1982,1169],{"class":200},[26,1984,834],{"class":36},[26,1986,837],{"class":200},[26,1988,840],{"class":36},[26,1990,698],{"class":32},[26,1992,845],{"class":36},[26,1994,1995],{"class":28,"line":208},[26,1996,238],{"class":36},[26,1998,1999,2002],{"class":28,"line":216},[26,2000,2001],{"class":32},"    do_small_step",[26,2003,144],{"class":36},[26,2005,2006],{"class":28,"line":223},[26,2007,262],{"class":36},[12,2009,2010],{},"通常比：",[16,2012,2014],{"className":18,"code":2013,"language":20,"meta":21,"style":21},"while (!token.stop_requested())\n{\n    do_one_huge_blocking_job();\n}\n",[23,2015,2016,2030,2034,2041],{"__ignoreMap":21},[26,2017,2018,2020,2022,2024,2026,2028],{"class":28,"line":29},[26,2019,1169],{"class":200},[26,2021,834],{"class":36},[26,2023,837],{"class":200},[26,2025,840],{"class":36},[26,2027,698],{"class":32},[26,2029,845],{"class":36},[26,2031,2032],{"class":28,"line":208},[26,2033,238],{"class":36},[26,2035,2036,2039],{"class":28,"line":216},[26,2037,2038],{"class":32},"    do_one_huge_blocking_job",[26,2040,144],{"class":36},[26,2042,2043],{"class":28,"line":223},[26,2044,262],{"class":36},[12,2046,2047],{},"更容易快速响应停止请求。",[77,2049],{},[87,2051,2053],{"id":2052},"stdstop_source",[23,2054,2055],{},"std::stop_source",[12,2057,2058],{},"前面说过：",[16,2060,2063],{"className":2061,"code":2062,"language":58,"meta":21},[56],"stop_token\n→ 观察停止请求\n",[23,2064,2062],{"__ignoreMap":21},[12,2066,2067],{},"那么谁负责发出停止请求？",[12,2069,2070,2071,2074],{},"除了 ",[23,2072,2073],{},"jthread.request_stop()","，标准库还提供：",[16,2076,2078],{"className":18,"code":2077,"language":20,"meta":21,"style":21},"std::stop_source\n",[23,2079,2080],{"__ignoreMap":21},[26,2081,2082,2084],{"class":28,"line":29},[26,2083,33],{"class":32},[26,2085,2086],{"class":36},"::stop_source\n",[12,2088,2089],{},"它可以理解成：",[541,2091,2092],{},[12,2093,2094],{},[42,2095,2096],{},"停止请求的控制端。",[12,2098,190],{},[16,2100,2102],{"className":18,"code":2101,"language":20,"meta":21,"style":21},"#include \u003Cprint>\n#include \u003Cstop_token>\n\nint main()\n{\n    std::stop_source source;\n\n    std::stop_token token = source.get_token();\n\n    std::println(\"{}\", token.stop_requested());\n\n    source.request_stop();\n\n    std::println(\"{}\", token.stop_requested());\n}\n",[23,2103,2104,2110,2116,2120,2128,2132,2139,2143,2160,2164,2185,2189,2198,2202,2220],{"__ignoreMap":21},[26,2105,2106,2108],{"class":28,"line":29},[26,2107,201],{"class":200},[26,2109,205],{"class":204},[26,2111,2112,2114],{"class":28,"line":208},[26,2113,201],{"class":200},[26,2115,767],{"class":204},[26,2117,2118],{"class":28,"line":216},[26,2119,220],{"emptyLinePlaceholder":219},[26,2121,2122,2124,2126],{"class":28,"line":223},[26,2123,273],{"class":200},[26,2125,276],{"class":32},[26,2127,232],{"class":36},[26,2129,2130],{"class":28,"line":235},[26,2131,238],{"class":36},[26,2133,2134,2136],{"class":28,"line":241},[26,2135,244],{"class":32},[26,2137,2138],{"class":36},"::stop_source source;\n",[26,2140,2141],{"class":28,"line":259},[26,2142,220],{"emptyLinePlaceholder":219},[26,2144,2145,2147,2150,2152,2155,2158],{"class":28,"line":265},[26,2146,244],{"class":32},[26,2148,2149],{"class":36},"::stop_token token ",[26,2151,1263],{"class":200},[26,2153,2154],{"class":36}," source.",[26,2156,2157],{"class":32},"get_token",[26,2159,144],{"class":36},[26,2161,2162],{"class":28,"line":270},[26,2163,220],{"emptyLinePlaceholder":219},[26,2165,2166,2168,2170,2172,2174,2177,2180,2182],{"class":28,"line":281},[26,2167,244],{"class":32},[26,2169,110],{"class":36},[26,2171,249],{"class":32},[26,2173,119],{"class":36},[26,2175,2176],{"class":204},"\"{}\"",[26,2178,2179],{"class":36},", token.",[26,2181,698],{"class":32},[26,2183,2184],{"class":36},"());\n",[26,2186,2187],{"class":28,"line":286},[26,2188,220],{"emptyLinePlaceholder":219},[26,2190,2191,2194,2196],{"class":28,"line":299},[26,2192,2193],{"class":36},"    source.",[26,2195,625],{"class":32},[26,2197,144],{"class":36},[26,2199,2200],{"class":28,"line":304},[26,2201,220],{"emptyLinePlaceholder":219},[26,2203,2204,2206,2208,2210,2212,2214,2216,2218],{"class":28,"line":311},[26,2205,244],{"class":32},[26,2207,110],{"class":36},[26,2209,249],{"class":32},[26,2211,119],{"class":36},[26,2213,2176],{"class":204},[26,2215,2179],{"class":36},[26,2217,698],{"class":32},[26,2219,2184],{"class":36},[26,2221,2222],{"class":28,"line":898},[26,2223,262],{"class":36},[12,2225,462],{},[16,2227,2230],{"className":2228,"code":2229,"language":58,"meta":21},[56],"false\ntrue\n",[23,2231,2229],{"__ignoreMap":21},[12,2233,2234],{},"整个关系可以理解成：",[16,2236,2239],{"className":2237,"code":2238,"language":58,"meta":21},[56],"stop_source\n    │\n    │ request_stop()\n    ↓\n共享停止状态\n    ↑\n    │ stop_requested()\nstop_token\n",[23,2240,2238],{"__ignoreMap":21},[12,2242,613],{},[16,2244,2246],{"className":18,"code":2245,"language":20,"meta":21,"style":21},"std::stop_source source;\n",[23,2247,2248],{"__ignoreMap":21},[26,2249,2250,2252],{"class":28,"line":29},[26,2251,33],{"class":32},[26,2253,2138],{"class":36},[12,2255,2256],{},"负责：",[16,2258,2261],{"className":2259,"code":2260,"language":58,"meta":21},[56],"发请求\n",[23,2262,2260],{"__ignoreMap":21},[12,2264,2265],{},"而：",[16,2267,2269],{"className":18,"code":2268,"language":20,"meta":21,"style":21},"std::stop_token token = source.get_token();\n",[23,2270,2271],{"__ignoreMap":21},[26,2272,2273,2275,2277,2279,2281,2283],{"class":28,"line":29},[26,2274,33],{"class":32},[26,2276,2149],{"class":36},[26,2278,1263],{"class":200},[26,2280,2154],{"class":36},[26,2282,2157],{"class":32},[26,2284,144],{"class":36},[12,2286,2256],{},[16,2288,2291],{"className":2289,"code":2290,"language":58,"meta":21},[56],"看请求\n",[23,2292,2290],{"__ignoreMap":21},[77,2294],{},[87,2296,2298,2299,2301],{"id":2297},"多个-stop_token-可以观察同一个停止状态","多个 ",[23,2300,661],{}," 可以观察同一个停止状态",[12,2303,190],{},[16,2305,2307],{"className":18,"code":2306,"language":20,"meta":21,"style":21},"std::stop_source source;\n\nstd::stop_token token1 = source.get_token();\nstd::stop_token token2 = source.get_token();\nstd::stop_token token3 = source.get_token();\n",[23,2308,2309,2315,2319,2334,2349],{"__ignoreMap":21},[26,2310,2311,2313],{"class":28,"line":29},[26,2312,33],{"class":32},[26,2314,2138],{"class":36},[26,2316,2317],{"class":28,"line":208},[26,2318,220],{"emptyLinePlaceholder":219},[26,2320,2321,2323,2326,2328,2330,2332],{"class":28,"line":216},[26,2322,33],{"class":32},[26,2324,2325],{"class":36},"::stop_token token1 ",[26,2327,1263],{"class":200},[26,2329,2154],{"class":36},[26,2331,2157],{"class":32},[26,2333,144],{"class":36},[26,2335,2336,2338,2341,2343,2345,2347],{"class":28,"line":223},[26,2337,33],{"class":32},[26,2339,2340],{"class":36},"::stop_token token2 ",[26,2342,1263],{"class":200},[26,2344,2154],{"class":36},[26,2346,2157],{"class":32},[26,2348,144],{"class":36},[26,2350,2351,2353,2356,2358,2360,2362],{"class":28,"line":235},[26,2352,33],{"class":32},[26,2354,2355],{"class":36},"::stop_token token3 ",[26,2357,1263],{"class":200},[26,2359,2154],{"class":36},[26,2361,2157],{"class":32},[26,2363,144],{"class":36},[12,2365,2366],{},"这三个 token 都关联到同一个停止状态。",[12,2368,2369],{},"当：",[16,2371,2373],{"className":18,"code":2372,"language":20,"meta":21,"style":21},"source.request_stop();\n",[23,2374,2375],{"__ignoreMap":21},[26,2376,2377,2380,2382],{"class":28,"line":29},[26,2378,2379],{"class":36},"source.",[26,2381,625],{"class":32},[26,2383,144],{"class":36},[12,2385,2386],{},"之后：",[16,2388,2390],{"className":18,"code":2389,"language":20,"meta":21,"style":21},"token1.stop_requested()\ntoken2.stop_requested()\ntoken3.stop_requested()\n",[23,2391,2392,2401,2410],{"__ignoreMap":21},[26,2393,2394,2397,2399],{"class":28,"line":29},[26,2395,2396],{"class":36},"token1.",[26,2398,698],{"class":32},[26,2400,232],{"class":36},[26,2402,2403,2406,2408],{"class":28,"line":208},[26,2404,2405],{"class":36},"token2.",[26,2407,698],{"class":32},[26,2409,232],{"class":36},[26,2411,2412,2415,2417],{"class":28,"line":216},[26,2413,2414],{"class":36},"token3.",[26,2416,698],{"class":32},[26,2418,232],{"class":36},[12,2420,2421],{},"都会变成：",[16,2423,2426],{"className":2424,"code":2425,"language":58,"meta":21},[56],"true\n",[23,2427,2425],{"__ignoreMap":21},[12,2429,2430,2431,2434],{},"所以 ",[23,2432,2433],{},"stop_source + stop_token"," 很适合表达：",[16,2436,2439],{"className":2437,"code":2438,"language":58,"meta":21},[56],"一个管理者\n    ↓\n统一发出停止请求\n    ↓\n多个任务 \u002F 对象\n    ↓\n一起观察同一个停止状态\n",[23,2440,2438],{"__ignoreMap":21},[77,2442],{},[87,2444,2446],{"id":2445},"stdstop_callback",[23,2447,2448],{},"std::stop_callback",[12,2450,2451],{},"有时候我们不想一直手动检查：",[16,2453,2454],{"className":18,"code":1200,"language":20,"meta":21,"style":21},[23,2455,2456],{"__ignoreMap":21},[26,2457,2458,2460,2462],{"class":28,"line":29},[26,2459,840],{"class":36},[26,2461,698],{"class":32},[26,2463,232],{"class":36},[12,2465,2466],{},"而是希望：",[541,2468,2469],{},[12,2470,2471],{},"一旦停止请求出现，就自动执行某个操作。",[12,2473,2474],{},"可以使用：",[16,2476,2478],{"className":18,"code":2477,"language":20,"meta":21,"style":21},"std::stop_callback\n",[23,2479,2480],{"__ignoreMap":21},[26,2481,2482,2484],{"class":28,"line":29},[26,2483,33],{"class":32},[26,2485,2486],{"class":36},"::stop_callback\n",[12,2488,190],{},[16,2490,2492],{"className":18,"code":2491,"language":20,"meta":21,"style":21},"#include \u003Cprint>\n#include \u003Cstop_token>\n\nint main()\n{\n    std::stop_source source;\n    std::stop_token token = source.get_token();\n\n    std::stop_callback callback(token, [] {\n        std::println(\"stop requested\");\n    });\n\n    source.request_stop();\n}\n",[23,2493,2494,2500,2506,2510,2518,2522,2528,2542,2546,2559,2574,2579,2583,2591],{"__ignoreMap":21},[26,2495,2496,2498],{"class":28,"line":29},[26,2497,201],{"class":200},[26,2499,205],{"class":204},[26,2501,2502,2504],{"class":28,"line":208},[26,2503,201],{"class":200},[26,2505,767],{"class":204},[26,2507,2508],{"class":28,"line":216},[26,2509,220],{"emptyLinePlaceholder":219},[26,2511,2512,2514,2516],{"class":28,"line":223},[26,2513,273],{"class":200},[26,2515,276],{"class":32},[26,2517,232],{"class":36},[26,2519,2520],{"class":28,"line":235},[26,2521,238],{"class":36},[26,2523,2524,2526],{"class":28,"line":241},[26,2525,244],{"class":32},[26,2527,2138],{"class":36},[26,2529,2530,2532,2534,2536,2538,2540],{"class":28,"line":259},[26,2531,244],{"class":32},[26,2533,2149],{"class":36},[26,2535,1263],{"class":200},[26,2537,2154],{"class":36},[26,2539,2157],{"class":32},[26,2541,144],{"class":36},[26,2543,2544],{"class":28,"line":265},[26,2545,220],{"emptyLinePlaceholder":219},[26,2547,2548,2550,2553,2556],{"class":28,"line":270},[26,2549,244],{"class":32},[26,2551,2552],{"class":36},"::stop_callback ",[26,2554,2555],{"class":32},"callback",[26,2557,2558],{"class":36},"(token, [] {\n",[26,2560,2561,2563,2565,2567,2569,2572],{"class":28,"line":281},[26,2562,855],{"class":32},[26,2564,110],{"class":36},[26,2566,249],{"class":32},[26,2568,119],{"class":36},[26,2570,2571],{"class":204},"\"stop requested\"",[26,2573,125],{"class":36},[26,2575,2576],{"class":28,"line":286},[26,2577,2578],{"class":36},"    });\n",[26,2580,2581],{"class":28,"line":299},[26,2582,220],{"emptyLinePlaceholder":219},[26,2584,2585,2587,2589],{"class":28,"line":304},[26,2586,2193],{"class":36},[26,2588,625],{"class":32},[26,2590,144],{"class":36},[26,2592,2593],{"class":28,"line":311},[26,2594,262],{"class":36},[12,2596,462],{},[16,2598,2601],{"className":2599,"code":2600,"language":58,"meta":21},[56],"stop requested\n",[23,2602,2600],{"__ignoreMap":21},[12,2604,723],{},[16,2606,2609],{"className":2607,"code":2608,"language":58,"meta":21},[56],"request_stop()\n      ↓\n停止状态改变\n      ↓\n已经注册的 stop_callback 被调用\n",[23,2610,2608],{"__ignoreMap":21},[12,2612,2613,2614,2616],{},"他如果是",[23,2615,524],{},"调用的话，那么顺序是：",[16,2618,2621],{"className":2619,"code":2620,"language":58,"meta":21},[56],"request_stop()\n    ↓\n同步执行 stop_callback\n    ↓\nrequest_stop() 返回\n    ↓\njoin()\n",[23,2622,2620],{"__ignoreMap":21},[12,2624,2625],{},"也就是说，callback 先于 join() 完成。std::jthread 的析构本身就是先调用 request_stop()，再调用 join()。",[12,2627,2628],{},"它很适合干一些很轻量的事情，例如：",[16,2630,2633],{"className":2631,"code":2632,"language":58,"meta":21},[56],"设置状态\n\n唤醒某个等待对象\n\n通知某个组件开始收尾\n",[23,2634,2632],{"__ignoreMap":21},[12,2636,2637],{},"但不建议在 callback 里面做：",[16,2639,2642],{"className":2640,"code":2641,"language":58,"meta":21},[56],"复杂计算\n长时间 IO\n长时间阻塞\n大量锁操作\n",[23,2643,2641],{"__ignoreMap":21},[12,2645,2646],{},"因为停止路径本身应该尽量简单、可控。",[12,2648,2649],{},"还有一个细节：",[12,2651,2652],{},"如果注册 callback 时，停止请求已经发生，那么 callback 可能会在注册过程中直接执行。",[12,2654,2655],{},"所以不要假设：",[16,2657,2660],{"className":2658,"code":2659,"language":58,"meta":21},[56],"callback 一定会在未来某个时间\n由另一个线程执行\n",[23,2661,2659],{"__ignoreMap":21},[77,2663],{},[80,2665,2667],{"id":2666},"jthread-的线程函数和生命周期操作","jthread 的线程函数和生命周期操作",[87,2669,2671,2673,2674],{"id":2670},"jthread-不一定非要使用-stop_token",[23,2672,524],{}," 不一定非要使用 ",[23,2675,661],{},[12,2677,2678,2680,2681,2683],{},[23,2679,74],{}," 也可以像普通 ",[23,2682,51],{}," 一样运行普通函数。",[12,2685,190],{},[16,2687,2689],{"className":18,"code":2688,"language":20,"meta":21,"style":21},"#include \u003Cprint>\n#include \u003Cthread>\n\nvoid work(int value)\n{\n    std::println(\"{}\", value);\n}\n\nint main()\n{\n    std::jthread thread(work, 42);\n}\n",[23,2690,2691,2697,2703,2707,2722,2726,2741,2745,2749,2757,2761,2777],{"__ignoreMap":21},[26,2692,2693,2695],{"class":28,"line":29},[26,2694,201],{"class":200},[26,2696,205],{"class":204},[26,2698,2699,2701],{"class":28,"line":208},[26,2700,201],{"class":200},[26,2702,213],{"class":204},[26,2704,2705],{"class":28,"line":216},[26,2706,220],{"emptyLinePlaceholder":219},[26,2708,2709,2711,2713,2715,2717,2720],{"class":28,"line":223},[26,2710,226],{"class":200},[26,2712,229],{"class":32},[26,2714,119],{"class":36},[26,2716,273],{"class":200},[26,2718,2719],{"class":818}," value",[26,2721,822],{"class":36},[26,2723,2724],{"class":28,"line":235},[26,2725,238],{"class":36},[26,2727,2728,2730,2732,2734,2736,2738],{"class":28,"line":241},[26,2729,244],{"class":32},[26,2731,110],{"class":36},[26,2733,249],{"class":32},[26,2735,119],{"class":36},[26,2737,2176],{"class":204},[26,2739,2740],{"class":36},", value);\n",[26,2742,2743],{"class":28,"line":259},[26,2744,262],{"class":36},[26,2746,2747],{"class":28,"line":265},[26,2748,220],{"emptyLinePlaceholder":219},[26,2750,2751,2753,2755],{"class":28,"line":270},[26,2752,273],{"class":200},[26,2754,276],{"class":32},[26,2756,232],{"class":36},[26,2758,2759],{"class":28,"line":281},[26,2760,238],{"class":36},[26,2762,2763,2765,2767,2769,2772,2775],{"class":28,"line":286},[26,2764,244],{"class":32},[26,2766,451],{"class":36},[26,2768,113],{"class":32},[26,2770,2771],{"class":36},"(work, ",[26,2773,2774],{"class":884},"42",[26,2776,125],{"class":36},[26,2778,2779],{"class":28,"line":299},[26,2780,262],{"class":36},[12,2782,462],{},[16,2784,2787],{"className":2785,"code":2786,"language":58,"meta":21},[56],"42\n",[23,2788,2786],{"__ignoreMap":21},[12,2790,2791],{},"这里：",[16,2793,2795],{"className":18,"code":2794,"language":20,"meta":21,"style":21},"void work(int value)\n",[23,2796,2797],{"__ignoreMap":21},[26,2798,2799,2801,2803,2805,2807,2809],{"class":28,"line":29},[26,2800,226],{"class":200},[26,2802,229],{"class":32},[26,2804,119],{"class":36},[26,2806,273],{"class":200},[26,2808,2719],{"class":818},[26,2810,822],{"class":36},[12,2812,2813,2814,45],{},"根本没有 ",[23,2815,661],{},[12,2817,2818],{},"没有关系。",[12,2820,2821,2823],{},[23,2822,524],{}," 会判断这个函数能不能接收自动提供的 stop token。",[12,2825,2826],{},"可以简单理解成：",[16,2828,2831],{"className":2829,"code":2830,"language":58,"meta":21},[56],"如果函数可以这样调用：\n\nworker(stop_token, args...)\n\n→ 自动传入 stop_token\n\n否则如果函数只能这样调用：\n\nworker(args...)\n\n→ 就像普通 thread 一样调用\n",[23,2832,2830],{"__ignoreMap":21},[12,2834,2835],{},"所以两种写法都可以：",[16,2837,2839],{"className":18,"code":2838,"language":20,"meta":21,"style":21},"void worker(std::stop_token token);\n",[23,2840,2841],{"__ignoreMap":21},[26,2842,2843,2845,2847,2849,2851,2853,2855,2857],{"class":28,"line":29},[26,2844,226],{"class":200},[26,2846,807],{"class":32},[26,2848,119],{"class":36},[26,2850,33],{"class":32},[26,2852,110],{"class":36},[26,2854,661],{"class":32},[26,2856,819],{"class":818},[26,2858,125],{"class":36},[12,2860,2861],{},"以及：",[16,2863,2865],{"className":18,"code":2864,"language":20,"meta":21,"style":21},"void worker();\n",[23,2866,2867],{"__ignoreMap":21},[26,2868,2869,2871,2873],{"class":28,"line":29},[26,2870,226],{"class":200},[26,2872,807],{"class":32},[26,2874,144],{"class":36},[77,2876],{},[87,2878,2880,2881,2883],{"id":2879},"带额外参数的-stop_token-线程函数","带额外参数的 ",[23,2882,661],{}," 线程函数",[12,2885,190],{},[16,2887,2889],{"className":18,"code":2888,"language":20,"meta":21,"style":21},"#include \u003Cprint>\n#include \u003Cstop_token>\n#include \u003Cthread>\n\nvoid worker(std::stop_token token, int id)\n{\n    std::println(\"worker {}\", id);\n\n    while (!token.stop_requested())\n    {\n        \u002F\u002F work\n    }\n}\n\nint main()\n{\n    std::jthread thread(worker, 7);\n\n    thread.request_stop();\n}\n",[23,2890,2891,2897,2903,2909,2913,2939,2943,2959,2963,2977,2981,2985,2989,2993,2997,3005,3009,3025,3029,3037],{"__ignoreMap":21},[26,2892,2893,2895],{"class":28,"line":29},[26,2894,201],{"class":200},[26,2896,205],{"class":204},[26,2898,2899,2901],{"class":28,"line":208},[26,2900,201],{"class":200},[26,2902,767],{"class":204},[26,2904,2905,2907],{"class":28,"line":216},[26,2906,201],{"class":200},[26,2908,213],{"class":204},[26,2910,2911],{"class":28,"line":223},[26,2912,220],{"emptyLinePlaceholder":219},[26,2914,2915,2917,2919,2921,2923,2925,2927,2929,2932,2934,2937],{"class":28,"line":235},[26,2916,226],{"class":200},[26,2918,807],{"class":32},[26,2920,119],{"class":36},[26,2922,33],{"class":32},[26,2924,110],{"class":36},[26,2926,661],{"class":32},[26,2928,819],{"class":818},[26,2930,2931],{"class":36},", ",[26,2933,273],{"class":200},[26,2935,2936],{"class":818}," id",[26,2938,822],{"class":36},[26,2940,2941],{"class":28,"line":241},[26,2942,238],{"class":36},[26,2944,2945,2947,2949,2951,2953,2956],{"class":28,"line":259},[26,2946,244],{"class":32},[26,2948,110],{"class":36},[26,2950,249],{"class":32},[26,2952,119],{"class":36},[26,2954,2955],{"class":204},"\"worker {}\"",[26,2957,2958],{"class":36},", id);\n",[26,2960,2961],{"class":28,"line":265},[26,2962,220],{"emptyLinePlaceholder":219},[26,2964,2965,2967,2969,2971,2973,2975],{"class":28,"line":270},[26,2966,831],{"class":200},[26,2968,834],{"class":36},[26,2970,837],{"class":200},[26,2972,840],{"class":36},[26,2974,698],{"class":32},[26,2976,845],{"class":36},[26,2978,2979],{"class":28,"line":281},[26,2980,850],{"class":36},[26,2982,2983],{"class":28,"line":286},[26,2984,1573],{"class":307},[26,2986,2987],{"class":28,"line":299},[26,2988,895],{"class":36},[26,2990,2991],{"class":28,"line":304},[26,2992,262],{"class":36},[26,2994,2995],{"class":28,"line":311},[26,2996,220],{"emptyLinePlaceholder":219},[26,2998,2999,3001,3003],{"class":28,"line":898},[26,3000,273],{"class":200},[26,3002,276],{"class":32},[26,3004,232],{"class":36},[26,3006,3007],{"class":28,"line":903},[26,3008,238],{"class":36},[26,3010,3011,3013,3015,3017,3020,3023],{"class":28,"line":919},[26,3012,244],{"class":32},[26,3014,451],{"class":36},[26,3016,113],{"class":32},[26,3018,3019],{"class":36},"(worker, ",[26,3021,3022],{"class":884},"7",[26,3024,125],{"class":36},[26,3026,3027],{"class":28,"line":924},[26,3028,220],{"emptyLinePlaceholder":219},[26,3030,3031,3033,3035],{"class":28,"line":929},[26,3032,990],{"class":36},[26,3034,625],{"class":32},[26,3036,144],{"class":36},[26,3038,3039],{"class":28,"line":938},[26,3040,262],{"class":36},[12,3042,2791],{},[16,3044,3046],{"className":18,"code":3045,"language":20,"meta":21,"style":21},"std::jthread thread(worker, 7);\n",[23,3047,3048],{"__ignoreMap":21},[26,3049,3050,3052,3054,3056,3058,3060,3062,3064,3066],{"class":28,"line":29},[26,3051,33],{"class":32},[26,3053,110],{"class":36},[26,3055,524],{"class":32},[26,3057,116],{"class":32},[26,3059,119],{"class":36},[26,3061,1057],{"class":32},[26,3063,2931],{"class":36},[26,3065,3022],{"class":884},[26,3067,125],{"class":36},[12,3069,3070],{},"可以理解成最终调用：",[16,3072,3074],{"className":18,"code":3073,"language":20,"meta":21,"style":21},"worker(自动提供的 stop_token, 7);\n",[23,3075,3076],{"__ignoreMap":21},[26,3077,3078,3080,3083,3085],{"class":28,"line":29},[26,3079,1057],{"class":32},[26,3081,3082],{"class":36},"(自动提供的 stop_token, ",[26,3084,3022],{"class":884},[26,3086,125],{"class":36},[12,3088,3089],{},"所以如果函数需要 stop token，参数顺序通常是：",[16,3091,3093],{"className":18,"code":3092,"language":20,"meta":21,"style":21},"void worker(std::stop_token token, 参数1, 参数2, ...)\n",[23,3094,3095],{"__ignoreMap":21},[26,3096,3097,3099,3101,3103,3105,3107,3109,3111],{"class":28,"line":29},[26,3098,226],{"class":200},[26,3100,807],{"class":32},[26,3102,119],{"class":36},[26,3104,33],{"class":32},[26,3106,110],{"class":36},[26,3108,661],{"class":32},[26,3110,819],{"class":818},[26,3112,3113],{"class":36},", 参数1, 参数2, ...)\n",[12,3115,190],{},[16,3117,3119],{"className":18,"code":3118,"language":20,"meta":21,"style":21},"void worker(\n    std::stop_token token,\n    int id,\n    std::string name);\n",[23,3120,3121,3130,3143,3152],{"__ignoreMap":21},[26,3122,3123,3125,3127],{"class":28,"line":29},[26,3124,226],{"class":200},[26,3126,807],{"class":32},[26,3128,3129],{"class":36},"(\n",[26,3131,3132,3134,3136,3138,3140],{"class":28,"line":208},[26,3133,244],{"class":32},[26,3135,110],{"class":36},[26,3137,661],{"class":32},[26,3139,819],{"class":818},[26,3141,3142],{"class":36},",\n",[26,3144,3145,3148,3150],{"class":28,"line":216},[26,3146,3147],{"class":200},"    int",[26,3149,2936],{"class":818},[26,3151,3142],{"class":36},[26,3153,3154,3156,3158,3161,3164],{"class":28,"line":223},[26,3155,244],{"class":32},[26,3157,110],{"class":36},[26,3159,3160],{"class":32},"string",[26,3162,3163],{"class":818}," name",[26,3165,125],{"class":36},[12,3167,3168],{},"创建：",[16,3170,3172],{"className":18,"code":3171,"language":20,"meta":21,"style":21},"std::jthread thread(worker, 7, \"camera\");\n",[23,3173,3174],{"__ignoreMap":21},[26,3175,3176,3178,3180,3182,3184,3186,3188,3190,3192,3194,3197],{"class":28,"line":29},[26,3177,33],{"class":32},[26,3179,110],{"class":36},[26,3181,524],{"class":32},[26,3183,116],{"class":32},[26,3185,119],{"class":36},[26,3187,1057],{"class":32},[26,3189,2931],{"class":36},[26,3191,3022],{"class":884},[26,3193,2931],{"class":36},[26,3195,3196],{"class":204},"\"camera\"",[26,3198,125],{"class":36},[12,3200,3201],{},"相当于：",[16,3203,3206],{"className":3204,"code":3205,"language":58,"meta":21},[56],"worker(\n    自动提供的 stop_token,\n    7,\n    \"camera\"\n)\n",[23,3207,3205],{"__ignoreMap":21},[77,3209],{},[87,3211,3213,3215,3216],{"id":3212},"jthread-仍然可以手动-join",[23,3214,524],{}," 仍然可以手动 ",[23,3217,347],{},[12,3219,3220,3221,3223],{},"虽然 ",[23,3222,524],{}," 会自动 join，但你仍然可以自己写：",[16,3225,3227],{"className":18,"code":3226,"language":20,"meta":21,"style":21},"std::jthread thread(work);\n\nthread.join();\n",[23,3228,3229,3245,3249],{"__ignoreMap":21},[26,3230,3231,3233,3235,3237,3239,3241,3243],{"class":28,"line":29},[26,3232,33],{"class":32},[26,3234,110],{"class":36},[26,3236,524],{"class":32},[26,3238,116],{"class":32},[26,3240,119],{"class":36},[26,3242,122],{"class":32},[26,3244,125],{"class":36},[26,3246,3247],{"class":28,"line":208},[26,3248,220],{"emptyLinePlaceholder":219},[26,3250,3251,3253,3255],{"class":28,"line":216},[26,3252,138],{"class":36},[26,3254,141],{"class":32},[26,3256,144],{"class":36},[12,3258,3259],{},"执行完：",[16,3261,3262],{"className":18,"code":131,"language":20,"meta":21,"style":21},[23,3263,3264],{"__ignoreMap":21},[26,3265,3266,3268,3270],{"class":28,"line":29},[26,3267,138],{"class":36},[26,3269,141],{"class":32},[26,3271,144],{"class":36},[12,3273,3274],{},"以后：",[16,3276,3278],{"className":18,"code":3277,"language":20,"meta":21,"style":21},"thread.joinable()\n",[23,3279,3280],{"__ignoreMap":21},[26,3281,3282,3284,3287],{"class":28,"line":29},[26,3283,138],{"class":36},[26,3285,3286],{"class":32},"joinable",[26,3288,232],{"class":36},[12,3290,3291],{},"会变成：",[16,3293,3296],{"className":3294,"code":3295,"language":58,"meta":21},[56],"false\n",[23,3297,3295],{"__ignoreMap":21},[12,3299,3300,3301,3303],{},"因为这个 ",[23,3302,524],{}," 已经不再关联一个可 join 的执行线程。",[12,3305,613],{},[16,3307,3310],{"className":3308,"code":3309,"language":58,"meta":21},[56],"自动 join\n",[23,3311,3309],{"__ignoreMap":21},[12,3313,3314],{},"并不代表：",[16,3316,3319],{"className":3317,"code":3318,"language":58,"meta":21},[56],"不能手动 join\n",[23,3320,3318],{"__ignoreMap":21},[12,3322,3323],{},"它只是意味着：",[541,3325,3326],{},[12,3327,3328],{},"如果你没手动处理，析构函数会帮你安全收尾。",[77,3330],{},[87,3332,3334,3336,3337,3340],{"id":3333},"jthread-也可以-detach但通常不推荐",[23,3335,524],{}," 也可以 ",[23,3338,3339],{},"detach()","，但通常不推荐",[12,3342,3343,3345],{},[23,3344,524],{}," 仍然提供：",[16,3347,3348],{"className":18,"code":150,"language":20,"meta":21,"style":21},[23,3349,3350],{"__ignoreMap":21},[26,3351,3352,3354,3356],{"class":28,"line":29},[26,3353,138],{"class":36},[26,3355,159],{"class":32},[26,3357,144],{"class":36},[12,3359,3360],{},"但这样做以后：",[16,3362,3365],{"className":3363,"code":3364,"language":58,"meta":21},[56],"jthread 不再拥有这个线程\n\n析构时也没办法再 join 它\n",[23,3366,3364],{"__ignoreMap":21},[12,3368,3369,3370,3372],{},"于是 ",[23,3371,524],{}," 最重要的 RAII 生命周期优势基本就没有了。",[12,3374,3375],{},"所以如果你发现自己准备写：",[16,3377,3378],{"className":18,"code":150,"language":20,"meta":21,"style":21},[23,3379,3380],{"__ignoreMap":21},[26,3381,3382,3384,3386],{"class":28,"line":29},[26,3383,138],{"class":36},[26,3385,159],{"class":32},[26,3387,144],{"class":36},[12,3389,3390],{},"最好先问几个问题：",[16,3392,3395],{"className":3393,"code":3394,"language":58,"meta":21},[56],"这个线程以后由谁负责？\n\n程序退出时它怎么结束？\n\n它访问的对象会不会已经析构？\n\n它访问的资源能活多久？\n",[23,3396,3394],{"__ignoreMap":21},[12,3398,3399],{},"除非你非常明确地知道线程生命周期怎么管理，否则一般不建议随便 detach。",[77,3401],{},[87,3403,3405,3408,3409],{"id":3404},"condition_variable_any-与-stop_token",[23,3406,3407],{},"condition_variable_any"," 与 ",[23,3410,661],{},[12,3412,3413],{},"前面提到一个问题：",[12,3415,3416],{},"如果线程正在：",[16,3418,3420],{"className":18,"code":3419,"language":20,"meta":21,"style":21},"condition_variable.wait(...)\n",[23,3421,3422],{"__ignoreMap":21},[26,3423,3424,3427,3430],{"class":28,"line":29},[26,3425,3426],{"class":36},"condition_variable.",[26,3428,3429],{"class":32},"wait",[26,3431,3432],{"class":36},"(...)\n",[12,3434,3435],{},"里面睡眠，那么只检查：",[16,3437,3438],{"className":18,"code":1200,"language":20,"meta":21,"style":21},[23,3439,3440],{"__ignoreMap":21},[26,3441,3442,3444,3446],{"class":28,"line":29},[26,3443,840],{"class":36},[26,3445,698],{"class":32},[26,3447,232],{"class":36},[12,3449,3450],{},"是不够的。",[12,3452,3453],{},"因为线程可能根本没机会执行到下一次检查。",[12,3455,3456],{},"C++20 的：",[16,3458,3460],{"className":18,"code":3459,"language":20,"meta":21,"style":21},"std::condition_variable_any\n",[23,3461,3462],{"__ignoreMap":21},[26,3463,3464,3466],{"class":28,"line":29},[26,3465,33],{"class":32},[26,3467,3468],{"class":36},"::condition_variable_any\n",[12,3470,3471,3472,3474],{},"提供了可以直接配合 ",[23,3473,661],{}," 的等待方式。",[12,3476,190],{},[16,3478,3480],{"className":18,"code":3479,"language":20,"meta":21,"style":21},"#include \u003Ccondition_variable>\n#include \u003Cmutex>\n#include \u003Cstop_token>\n#include \u003Cthread>\n\nstd::mutex mutex;\nstd::condition_variable_any cv;\n\nbool ready = false;\n\nvoid worker(std::stop_token token)\n{\n    std::unique_lock lock(mutex);\n\n    bool condition_met = cv.wait(\n        lock,\n        token,\n        [] {\n            return ready;\n        });\n\n    if (!condition_met)\n    {\n        \u002F\u002F 没等到 ready == true，\n        \u002F\u002F 而是因为停止请求结束等待\n        return;\n    }\n\n    \u002F\u002F ready == true\n}\n",[23,3481,3482,3489,3496,3502,3508,3512,3519,3526,3530,3544,3548,3566,3570,3583,3587,3604,3609,3614,3619,3627,3632,3636,3648,3652,3657,3662,3669,3674,3679,3685],{"__ignoreMap":21},[26,3483,3484,3486],{"class":28,"line":29},[26,3485,201],{"class":200},[26,3487,3488],{"class":204}," \u003Ccondition_variable>\n",[26,3490,3491,3493],{"class":28,"line":208},[26,3492,201],{"class":200},[26,3494,3495],{"class":204}," \u003Cmutex>\n",[26,3497,3498,3500],{"class":28,"line":216},[26,3499,201],{"class":200},[26,3501,767],{"class":204},[26,3503,3504,3506],{"class":28,"line":223},[26,3505,201],{"class":200},[26,3507,213],{"class":204},[26,3509,3510],{"class":28,"line":235},[26,3511,220],{"emptyLinePlaceholder":219},[26,3513,3514,3516],{"class":28,"line":241},[26,3515,33],{"class":32},[26,3517,3518],{"class":36},"::mutex mutex;\n",[26,3520,3521,3523],{"class":28,"line":259},[26,3522,33],{"class":32},[26,3524,3525],{"class":36},"::condition_variable_any cv;\n",[26,3527,3528],{"class":28,"line":265},[26,3529,220],{"emptyLinePlaceholder":219},[26,3531,3532,3534,3537,3539,3542],{"class":28,"line":270},[26,3533,1248],{"class":200},[26,3535,3536],{"class":36}," ready ",[26,3538,1263],{"class":200},[26,3540,3541],{"class":884}," false",[26,3543,796],{"class":36},[26,3545,3546],{"class":28,"line":281},[26,3547,220],{"emptyLinePlaceholder":219},[26,3549,3550,3552,3554,3556,3558,3560,3562,3564],{"class":28,"line":286},[26,3551,226],{"class":200},[26,3553,807],{"class":32},[26,3555,119],{"class":36},[26,3557,33],{"class":32},[26,3559,110],{"class":36},[26,3561,661],{"class":32},[26,3563,819],{"class":818},[26,3565,822],{"class":36},[26,3567,3568],{"class":28,"line":299},[26,3569,238],{"class":36},[26,3571,3572,3574,3577,3580],{"class":28,"line":304},[26,3573,244],{"class":32},[26,3575,3576],{"class":36},"::unique_lock ",[26,3578,3579],{"class":32},"lock",[26,3581,3582],{"class":36},"(mutex);\n",[26,3584,3585],{"class":28,"line":311},[26,3586,220],{"emptyLinePlaceholder":219},[26,3588,3589,3592,3595,3597,3600,3602],{"class":28,"line":898},[26,3590,3591],{"class":200},"    bool",[26,3593,3594],{"class":36}," condition_met ",[26,3596,1263],{"class":200},[26,3598,3599],{"class":36}," cv.",[26,3601,3429],{"class":32},[26,3603,3129],{"class":36},[26,3605,3606],{"class":28,"line":903},[26,3607,3608],{"class":36},"        lock,\n",[26,3610,3611],{"class":28,"line":919},[26,3612,3613],{"class":36},"        token,\n",[26,3615,3616],{"class":28,"line":924},[26,3617,3618],{"class":36},"        [] {\n",[26,3620,3621,3624],{"class":28,"line":929},[26,3622,3623],{"class":200},"            return",[26,3625,3626],{"class":36}," ready;\n",[26,3628,3629],{"class":28,"line":938},[26,3630,3631],{"class":36},"        });\n",[26,3633,3634],{"class":28,"line":943},[26,3635,220],{"emptyLinePlaceholder":219},[26,3637,3638,3641,3643,3645],{"class":28,"line":955},[26,3639,3640],{"class":200},"    if",[26,3642,834],{"class":36},[26,3644,837],{"class":200},[26,3646,3647],{"class":36},"condition_met)\n",[26,3649,3650],{"class":28,"line":960},[26,3651,850],{"class":36},[26,3653,3654],{"class":28,"line":982},[26,3655,3656],{"class":307},"        \u002F\u002F 没等到 ready == true，\n",[26,3658,3659],{"class":28,"line":987},[26,3660,3661],{"class":307},"        \u002F\u002F 而是因为停止请求结束等待\n",[26,3663,3664,3667],{"class":28,"line":997},[26,3665,3666],{"class":200},"        return",[26,3668,796],{"class":36},[26,3670,3672],{"class":28,"line":3671},27,[26,3673,895],{"class":36},[26,3675,3677],{"class":28,"line":3676},28,[26,3678,220],{"emptyLinePlaceholder":219},[26,3680,3682],{"class":28,"line":3681},29,[26,3683,3684],{"class":307},"    \u002F\u002F ready == true\n",[26,3686,3688],{"class":28,"line":3687},30,[26,3689,262],{"class":36},[12,3691,3692],{},"可以把这次等待理解成：",[16,3694,3697],{"className":3695,"code":3696,"language":58,"meta":21},[56],"等待两个条件中的任意一个：\n\n1. ready == true\n\n或者\n\n2. 收到停止请求\n",[23,3698,3696],{"__ignoreMap":21},[12,3700,3701],{},"如果：",[16,3703,3705],{"className":18,"code":3704,"language":20,"meta":21,"style":21},"condition_met == true\n",[23,3706,3707],{"__ignoreMap":21},[26,3708,3709,3712,3715],{"class":28,"line":29},[26,3710,3711],{"class":36},"condition_met ",[26,3713,3714],{"class":200},"==",[26,3716,3717],{"class":884}," true\n",[12,3719,3720],{},"表示谓词：",[16,3722,3724],{"className":18,"code":3723,"language":20,"meta":21,"style":21},"ready == true\n",[23,3725,3726],{"__ignoreMap":21},[26,3727,3728,3731,3733],{"class":28,"line":29},[26,3729,3730],{"class":36},"ready ",[26,3732,3714],{"class":200},[26,3734,3717],{"class":884},[12,3736,3737],{},"成立。",[12,3739,3701],{},[16,3741,3743],{"className":18,"code":3742,"language":20,"meta":21,"style":21},"condition_met == false\n",[23,3744,3745],{"__ignoreMap":21},[26,3746,3747,3749,3751],{"class":28,"line":29},[26,3748,3711],{"class":36},[26,3750,3714],{"class":200},[26,3752,3753],{"class":884}," false\n",[12,3755,3756,3757,3760],{},"说明这次等待并不是因为 ",[23,3758,3759],{},"ready"," 成立而结束，通常就是因为收到了停止请求。",[12,3762,3763,3764,3766],{},"这样工作线程即使正在条件变量里等待，也能够响应 ",[23,3765,524],{}," 的停止协议。",[77,3768],{},[80,3770,3771],{"id":3771},"选择与常见错误",[87,3773,3775,3777,3778,3780],{"id":3774},"stdthread-和-stdjthread-对比",[23,3776,51],{}," 和 ",[23,3779,74],{}," 对比",[3782,3783,3784,3803],"table",{},[3785,3786,3787],"thead",{},[3788,3789,3790,3794,3799],"tr",{},[3791,3792,3793],"th",{},"特性",[3791,3795,3797],{"align":3796},"right",[23,3798,51],{},[3791,3800,3801],{"align":3796},[23,3802,74],{},[3804,3805,3806,3818,3828,3839,3849,3859,3871,3880,3891],"tbody",{},[3788,3807,3808,3812,3815],{},[3809,3810,3811],"td",{},"引入版本",[3809,3813,3814],{"align":3796},"C++11",[3809,3816,3817],{"align":3796},"C++20",[3788,3819,3820,3823,3826],{},[3809,3821,3822],{},"创建线程",[3809,3824,3825],{"align":3796},"✅",[3809,3827,3825],{"align":3796},[3788,3829,3830,3835,3837],{},[3809,3831,3832,3833],{},"手动 ",[23,3834,347],{},[3809,3836,3825],{"align":3796},[3809,3838,3825],{"align":3796},[3788,3840,3841,3845,3847],{},[3809,3842,3832,3843],{},[23,3844,3339],{},[3809,3846,3825],{"align":3796},[3809,3848,3825],{"align":3796},[3788,3850,3851,3854,3857],{},[3809,3852,3853],{},"析构时自动收尾",[3809,3855,3856],{"align":3796},"❌",[3809,3858,3825],{"align":3796},[3788,3860,3861,3867,3869],{},[3809,3862,3863,3864],{},"joinable 状态析构会 ",[23,3865,3866],{},"terminate()",[3809,3868,3825],{"align":3796},[3809,3870,3856],{"align":3796},[3788,3872,3873,3876,3878],{},[3809,3874,3875],{},"自带停止请求机制",[3809,3877,3856],{"align":3796},[3809,3879,3825],{"align":3796},[3788,3881,3882,3887,3889],{},[3809,3883,3884,3885],{},"自动提供 ",[23,3886,661],{},[3809,3888,3856],{"align":3796},[3809,3890,3825],{"align":3796},[3788,3892,3893,3896,3899],{},[3809,3894,3895],{},"适合长期可停止 worker",[3809,3897,3898],{"align":3796},"一般",[3809,3900,3825],{"align":3796},[12,3902,3903],{},"如果项目可以使用 C++20，对于这种线程：",[16,3905,3908],{"className":3906,"code":3907,"language":58,"meta":21},[56],"启动\n↓\n持续运行\n↓\n程序退出时请求停止\n↓\n安全结束\n",[23,3909,3907],{"__ignoreMap":21},[12,3911,3912],{},"通常优先考虑：",[16,3914,3915],{"className":18,"code":19,"language":20,"meta":21,"style":21},[23,3916,3917],{"__ignoreMap":21},[26,3918,3919,3921],{"class":28,"line":29},[26,3920,33],{"class":32},[26,3922,37],{"class":36},[77,3924],{},[87,3926,3928,3777,3931,3933],{"id":3927},"atomicbool-running-和-stop_token-怎么选",[23,3929,3930],{},"atomic\u003Cbool> running",[23,3932,661],{}," 怎么选",[12,3935,3936],{},"传统代码经常这样写：",[16,3938,3940],{"className":18,"code":3939,"language":20,"meta":21,"style":21},"std::atomic\u003Cbool> running{true};\n\nvoid worker()\n{\n    while (running.load())\n    {\n        \u002F\u002F work\n    }\n}\n",[23,3941,3942,3961,3965,3973,3977,3989,3993,3997,4001],{"__ignoreMap":21},[26,3943,3944,3946,3949,3952,3955,3958],{"class":28,"line":29},[26,3945,33],{"class":32},[26,3947,3948],{"class":36},"::atomic",[26,3950,3951],{"class":200},"\u003Cbool>",[26,3953,3954],{"class":36}," running{",[26,3956,3957],{"class":884},"true",[26,3959,3960],{"class":36},"};\n",[26,3962,3963],{"class":28,"line":208},[26,3964,220],{"emptyLinePlaceholder":219},[26,3966,3967,3969,3971],{"class":28,"line":216},[26,3968,226],{"class":200},[26,3970,807],{"class":32},[26,3972,232],{"class":36},[26,3974,3975],{"class":28,"line":223},[26,3976,238],{"class":36},[26,3978,3979,3981,3984,3987],{"class":28,"line":235},[26,3980,831],{"class":200},[26,3982,3983],{"class":36}," (running.",[26,3985,3986],{"class":32},"load",[26,3988,845],{"class":36},[26,3990,3991],{"class":28,"line":241},[26,3992,850],{"class":36},[26,3994,3995],{"class":28,"line":259},[26,3996,1573],{"class":307},[26,3998,3999],{"class":28,"line":265},[26,4000,895],{"class":36},[26,4002,4003],{"class":28,"line":270},[26,4004,262],{"class":36},[12,4006,4007],{},"停止时：",[16,4009,4011],{"className":18,"code":4010,"language":20,"meta":21,"style":21},"running.store(false);\n",[23,4012,4013],{"__ignoreMap":21},[26,4014,4015,4018,4021,4023,4026],{"class":28,"line":29},[26,4016,4017],{"class":36},"running.",[26,4019,4020],{"class":32},"store",[26,4022,119],{"class":36},[26,4024,4025],{"class":884},"false",[26,4027,125],{"class":36},[12,4029,4030],{},"这种写法没有问题。",[12,4032,4033],{},"对于非常简单的线程，它甚至很直观。",[12,4035,190],{},[16,4037,4040],{"className":4038,"code":4039,"language":58,"meta":21},[56],"running == true\n→ 继续运行\n\nrunning == false\n→ 停止\n",[23,4041,4039],{"__ignoreMap":21},[12,4043,4044],{},"但是：",[16,4046,4048],{"className":18,"code":4047,"language":20,"meta":21,"style":21},"std::stop_token\n",[23,4049,4050],{"__ignoreMap":21},[26,4051,4052,4054],{"class":28,"line":29},[26,4053,33],{"class":32},[26,4055,4056],{"class":36},"::stop_token\n",[12,4058,4059],{},"提供的是一套标准化的停止协议。",[12,4061,4062],{},"它可以和：",[16,4064,4067],{"className":4065,"code":4066,"language":58,"meta":21},[56],"std::jthread\n\nstd::stop_source\n\nstd::stop_callback\n\nstd::condition_variable_any\n",[23,4068,4066],{"__ignoreMap":21},[12,4070,4071],{},"直接配合。",[12,4073,4074],{},"可以理解成：",[16,4076,4079],{"className":4077,"code":4078,"language":58,"meta":21},[56],"atomic\u003Cbool>\n\n→ 只是一个线程安全的 bool\n→ “true \u002F false 到底是什么意思”由你自己规定\n",[23,4080,4078],{"__ignoreMap":21},[12,4082,2265],{},[16,4084,4087],{"className":4085,"code":4086,"language":58,"meta":21},[56],"stop_token\n\n→ 专门表达“停止请求”\n→ 标准库里的多个工具都认识这种协议\n",[23,4088,4086],{"__ignoreMap":21},[12,4090,1752],{},[16,4092,4095],{"className":4093,"code":4094,"language":58,"meta":21},[56],"非常简单的开关\n→ atomic\u003Cbool> 完全可以\n\n明确的线程停止生命周期\n→ jthread + stop_token 更合适\n",[23,4096,4094],{"__ignoreMap":21},[77,4098],{},[87,4100,4101],{"id":4101},"常见错误",[656,4103,4105,4106,4108],{"id":4104},"错误以为-request_stop-会强制杀死线程","错误：以为 ",[23,4107,1116],{}," 会强制杀死线程",[12,4110,4111],{},"错误理解：",[16,4113,4116],{"className":4114,"code":4115,"language":58,"meta":21},[56],"request_stop()\n→ 线程立刻消失\n",[23,4117,4115],{"__ignoreMap":21},[12,4119,4120],{},"正确理解：",[16,4122,4125],{"className":4123,"code":4124,"language":58,"meta":21},[56],"request_stop()\n→ 发出停止请求\n→ 工作线程自己检查并退出\n",[23,4126,4124],{"__ignoreMap":21},[77,4128],{},[656,4130,4132,4133],{"id":4131},"错误worker-从来不检查-stop_requested","错误：worker 从来不检查 ",[23,4134,4135],{},"stop_requested()",[12,4137,190],{},[16,4139,4141],{"className":18,"code":4140,"language":20,"meta":21,"style":21},"void worker(std::stop_token)\n{\n    while (true)\n    {\n        do_work();\n    }\n}\n",[23,4142,4143,4159,4163,4173,4177,4184,4188],{"__ignoreMap":21},[26,4144,4145,4147,4149,4151,4153,4155,4157],{"class":28,"line":29},[26,4146,226],{"class":200},[26,4148,807],{"class":32},[26,4150,119],{"class":36},[26,4152,33],{"class":32},[26,4154,110],{"class":36},[26,4156,661],{"class":32},[26,4158,822],{"class":36},[26,4160,4161],{"class":28,"line":208},[26,4162,238],{"class":36},[26,4164,4165,4167,4169,4171],{"class":28,"line":216},[26,4166,831],{"class":200},[26,4168,834],{"class":36},[26,4170,3957],{"class":884},[26,4172,822],{"class":36},[26,4174,4175],{"class":28,"line":223},[26,4176,850],{"class":36},[26,4178,4179,4182],{"class":28,"line":235},[26,4180,4181],{"class":32},"        do_work",[26,4183,144],{"class":36},[26,4185,4186],{"class":28,"line":241},[26,4187,895],{"class":36},[26,4189,4190],{"class":28,"line":259},[26,4191,262],{"class":36},[12,4193,4194,4195,4197],{},"即使 ",[23,4196,524],{}," 析构时自动：",[16,4199,4201],{"className":18,"code":4200,"language":20,"meta":21,"style":21},"request_stop();\n",[23,4202,4203],{"__ignoreMap":21},[26,4204,4205,4207],{"class":28,"line":29},[26,4206,625],{"class":32},[26,4208,144],{"class":36},[12,4210,4211],{},"这个线程也不会退出。",[12,4213,4214],{},"最终析构中的：",[16,4216,4218],{"className":18,"code":4217,"language":20,"meta":21,"style":21},"join();\n",[23,4219,4220],{"__ignoreMap":21},[26,4221,4222,4224],{"class":28,"line":29},[26,4223,141],{"class":32},[26,4225,144],{"class":36},[12,4227,4228],{},"会一直等。",[77,4230],{},[656,4232,4234],{"id":4233},"错误检查了停止请求但中间阻塞太久","错误：检查了停止请求，但中间阻塞太久",[12,4236,190],{},[16,4238,4240],{"className":18,"code":4239,"language":20,"meta":21,"style":21},"while (!token.stop_requested())\n{\n    blocking_operation(); \u002F\u002F 一卡几十秒\n}\n",[23,4241,4242,4256,4260,4270],{"__ignoreMap":21},[26,4243,4244,4246,4248,4250,4252,4254],{"class":28,"line":29},[26,4245,1169],{"class":200},[26,4247,834],{"class":36},[26,4249,837],{"class":200},[26,4251,840],{"class":36},[26,4253,698],{"class":32},[26,4255,845],{"class":36},[26,4257,4258],{"class":28,"line":208},[26,4259,238],{"class":36},[26,4261,4262,4264,4267],{"class":28,"line":216},[26,4263,1890],{"class":32},[26,4265,4266],{"class":36},"();",[26,4268,4269],{"class":307}," \u002F\u002F 一卡几十秒\n",[26,4271,4272],{"class":28,"line":223},[26,4273,262],{"class":36},[12,4275,4276],{},"停止请求虽然已经发出，但线程要等到阻塞操作返回后才能再次检查。",[77,4278],{},[656,4280,4282,4283,4285,4286],{"id":4281},"错误用了-jthread-又随手-detach","错误：用了 ",[23,4284,524],{}," 又随手 ",[23,4287,3339],{},[12,4289,4290],{},"这样会失去：",[16,4292,4295],{"className":4293,"code":4294,"language":58,"meta":21},[56],"自动 join\n自动停止请求\nRAII 生命周期管理\n",[23,4296,4294],{"__ignoreMap":21},[12,4298,4299],{},"这些主要优势。",[77,4301],{},[656,4303,4305,4306,4309],{"id":4304},"错误在-stop_callback-里做大量复杂工作","错误：在 ",[23,4307,4308],{},"stop_callback"," 里做大量复杂工作",[12,4311,4312],{},"callback 更适合：",[16,4314,4317],{"className":4315,"code":4316,"language":58,"meta":21},[56],"轻量通知\n设置状态\n唤醒等待者\n",[23,4318,4316],{"__ignoreMap":21},[12,4320,4321],{},"而不是承担复杂业务逻辑。",[77,4323],{},[656,4325,4327],{"id":4326},"错误以为收到停止请求就会立刻终止线程重要","错误：以为“收到停止请求”就会立刻终止线程（重要）",[12,4329,4330,4332],{},[23,4331,1116],{}," 只是发出停止请求，并不会强制中断工作线程。",[12,4334,4335,4336,4339],{},"工作线程通常会在某些",[42,4337,4338],{},"安全检查点","主动检查：",[16,4341,4342],{"className":18,"code":1200,"language":20,"meta":21,"style":21},[23,4343,4344],{"__ignoreMap":21},[26,4345,4346,4348,4350],{"class":28,"line":29},[26,4347,840],{"class":36},[26,4349,698],{"class":32},[26,4351,232],{"class":36},[12,4353,190],{},[16,4355,4357],{"className":18,"code":4356,"language":20,"meta":21,"style":21},"while (!token.stop_requested())\n{\n    finish_one_small_task();\n}\n",[23,4358,4359,4373,4377,4384],{"__ignoreMap":21},[26,4360,4361,4363,4365,4367,4369,4371],{"class":28,"line":29},[26,4362,1169],{"class":200},[26,4364,834],{"class":36},[26,4366,837],{"class":200},[26,4368,840],{"class":36},[26,4370,698],{"class":32},[26,4372,845],{"class":36},[26,4374,4375],{"class":28,"line":208},[26,4376,238],{"class":36},[26,4378,4379,4382],{"class":28,"line":216},[26,4380,4381],{"class":32},"    finish_one_small_task",[26,4383,144],{"class":36},[26,4385,4386],{"class":28,"line":223},[26,4387,262],{"class":36},[12,4389,4390,4391,4394],{},"如果停止请求恰好在 ",[23,4392,4393],{},"finish_one_small_task()"," 执行过程中到来，这个函数不会被强行执行到一半就终止。",[12,4396,4397],{},"线程通常会先完成当前这一小块工作，然后回到循环条件：",[16,4399,4400],{"className":18,"code":1200,"language":20,"meta":21,"style":21},[23,4401,4402],{"__ignoreMap":21},[26,4403,4404,4406,4408],{"class":28,"line":29},[26,4405,840],{"class":36},[26,4407,698],{"class":32},[26,4409,232],{"class":36},[12,4411,4412],{},"发现停止请求后，再退出循环并结束线程。",[12,4414,4074],{},[16,4416,4419],{"className":4417,"code":4418,"language":58,"meta":21},[56],"收到停止请求\n↓\n完成当前不能被随意打断的小任务\n↓\n到达安全检查点\n↓\n发现 stop_requested() == true\n↓\n退出循环\n↓\n完成必要的收尾\n↓\n线程结束\n",[23,4420,4418],{"__ignoreMap":21},[12,4422,1363,4423,4425],{},[23,4424,347],{}," 的作用只是：",[541,4427,4428],{},[12,4429,4430],{},"等待这个线程真正结束。",[12,4432,4433],{},"所以典型关系是：",[16,4435,4438],{"className":4436,"code":4437,"language":58,"meta":21},[56],"request_stop()\n→ 请求线程停止\n\nworker 在安全位置响应请求并退出\n\njoin()\n→ 等待 worker 退出完成\n",[23,4439,4437],{"__ignoreMap":21},[12,4441,4442],{},"所谓“合适、安全的位置”，就是线程状态已经完整、资源处于一致状态，此时退出不会留下半完成操作的位置。",[12,4444,4445],{},"安全点 = 可以开始退出的位置；函数 return = 线程真正退出。",[12,4447,4448],{},"所以可以这么理解例子中的worker函数 返回 ≈ 这个线程执行结束。",[77,4450],{},[80,4452,4453],{"id":4453},"小结",[12,4455,4456,667],{},[23,4457,74],{},[541,4459,4460],{},[12,4461,4462],{},[42,4463,4464,4465,45],{},"带 RAII 生命周期管理和标准停止协议的 ",[23,4466,51],{},[12,4468,4469],{},"最重要的几个点：",[16,4471,4474],{"className":4472,"code":4473,"language":58,"meta":21},[56],"std::thread\n→ 必须自己保证 join() \u002F detach()\n\nstd::jthread\n→ 析构时自动 request_stop() + join()\n",[23,4475,4473],{"__ignoreMap":21},[12,4477,4478],{},"停止机制：",[16,4480,4483],{"className":4481,"code":4482,"language":58,"meta":21},[56],"request_stop()\n→ 发出停止请求\n\nstop_token.stop_requested()\n→ 查看是否收到停止请求\n",[23,4484,4482],{"__ignoreMap":21},[12,4486,4487],{},"它是：",[16,4489,4492],{"className":4490,"code":4491,"language":58,"meta":21},[56],"协作式停止\n",[23,4493,4491],{"__ignoreMap":21},[12,4495,586],{},[16,4497,4500],{"className":4498,"code":4499,"language":58,"meta":21},[56],"强制杀死线程\n",[23,4501,4499],{"__ignoreMap":21},[12,4503,4504],{},"另外：",[16,4506,4509],{"className":4507,"code":4508,"language":58,"meta":21},[56],"stop_source\n→ 发出停止请求\n\nstop_token\n→ 观察停止请求\n\nstop_callback\n→ 停止请求出现时执行回调\n",[23,4510,4508],{"__ignoreMap":21},[12,4512,4513],{},"对于 C++20 中“启动后持续运行、退出时需要安全停止”的后台线程，一般可以优先考虑：",[16,4515,4517],{"className":18,"code":4516,"language":20,"meta":21,"style":21},"std::jthread + std::stop_token\n",[23,4518,4519],{"__ignoreMap":21},[26,4520,4521,4523,4525,4528,4530],{"class":28,"line":29},[26,4522,33],{"class":32},[26,4524,451],{"class":36},[26,4526,4527],{"class":200},"+",[26,4529,788],{"class":32},[26,4531,4056],{"class":36},[12,4533,586],{},[16,4535,4537],{"className":18,"code":4536,"language":20,"meta":21,"style":21},"std::thread + 手写生命周期管理 + 自定义 atomic\u003Cbool> 停止协议\n",[23,4538,4539],{"__ignoreMap":21},[26,4540,4541,4543,4545,4547,4550,4552,4555,4557],{"class":28,"line":29},[26,4542,33],{"class":32},[26,4544,291],{"class":36},[26,4546,4527],{"class":200},[26,4548,4549],{"class":36}," 手写生命周期管理 ",[26,4551,4527],{"class":200},[26,4553,4554],{"class":36}," 自定义 atomic",[26,4556,3951],{"class":200},[26,4558,4559],{"class":36}," 停止协议\n",[4561,4562,4563],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":21,"searchDepth":208,"depth":208,"links":4565},[4566,4575,4592,4604,4611],{"id":82,"depth":208,"text":4567,"children":4568},"为什么需要 std::jthread",[4569,4571,4573],{"id":89,"depth":216,"text":4570},"std::thread 的问题",{"id":371,"depth":216,"text":4572},"std::jthread 会自动处理线程结束",{"id":559,"depth":216,"text":4574},"jthread 不会强制杀死线程",{"id":647,"depth":208,"text":648,"children":4576},[4577,4578,4580,4581,4583,4584,4586,4587,4588,4589,4591],{"id":651,"depth":216,"text":654},{"id":734,"depth":216,"text":4579},"jthread 可以自动传入 stop_token",{"id":625,"depth":216,"text":1116},{"id":1237,"depth":216,"text":4582},"request_stop() 的返回值",{"id":1305,"depth":216,"text":1308},{"id":1396,"depth":216,"text":4585},"jthread 析构时到底发生什么",{"id":1646,"depth":216,"text":1647},{"id":1859,"depth":216,"text":1859},{"id":2052,"depth":216,"text":2055},{"id":2297,"depth":216,"text":4590},"多个 stop_token 可以观察同一个停止状态",{"id":2445,"depth":216,"text":2448},{"id":2666,"depth":208,"text":2667,"children":4593},[4594,4596,4598,4600,4602],{"id":2670,"depth":216,"text":4595},"jthread 不一定非要使用 stop_token",{"id":2879,"depth":216,"text":4597},"带额外参数的 stop_token 线程函数",{"id":3212,"depth":216,"text":4599},"jthread 仍然可以手动 join()",{"id":3333,"depth":216,"text":4601},"jthread 也可以 detach()，但通常不推荐",{"id":3404,"depth":216,"text":4603},"condition_variable_any 与 stop_token",{"id":3771,"depth":208,"text":3771,"children":4605},[4606,4608,4610],{"id":3774,"depth":216,"text":4607},"std::thread 和 std::jthread 对比",{"id":3927,"depth":216,"text":4609},"atomic\u003Cbool> running 和 stop_token 怎么选",{"id":4101,"depth":216,"text":4101},{"id":4453,"depth":208,"text":4453},"2000-1900-1600","2023-10-05","2023-10-05-cplusplus-jiao-xue","\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue","Cplusplus教学","md",false,{},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-1600-jthread-stop-token",{"title":5,"description":14},"wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-1600-jthread-stop-token","xN4NcOAisGe-Ncl8YzwigNnhZE19D_lLfVrSl-Li5QM",[4625,4632,4638,4644,4650,4656,4662,4668,4674,4680,4686,4692,4698,4704,4710,4716,4722,4728,4734,4740,4746,4752,4758,4764,4770,4776,4782,4788,4794,4800,4806,4812,4818,4824,4830,4836,4842,4848,4854,4860,4866,4872,4877,4883,4889,4895,4901,4907,4913,4919,4925,4931,4937,4943,4949,4955,4961,4967,4973,4979,4985,4991,4996,5002,5008,5014,5020,5022,5028,5034,5040,5046,5052,5058,5064,5070,5076,5082,5088,5094,5100,5106,5112,5118,5124,5130,5136,5142,5148,5154,5160,5166],{"path":4626,"stem":4627,"title":4628,"authors":4629,"date":4613,"chapterOrder":4630,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0100-c-kai-fa-huan-jing-da-jian-yu-ce-shi","wiki\u002F2023-10-05-Cplusplus教学\u002F0100-C++开发环境搭建与测试","C++开发环境搭建与测试",[7],"0100",0,{"path":4633,"stem":4634,"title":4635,"authors":4636,"date":4613,"chapterOrder":4637,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0200-c-ji-chu-chu-shi","wiki\u002F2023-10-05-Cplusplus教学\u002F0200-C++基础初识","C++基础初识",[7],"0200",{"path":4639,"stem":4640,"title":4641,"authors":4642,"date":4613,"chapterOrder":4643,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0300-shu-ju-lei-xing-yu-shu-ju-cun-fang","wiki\u002F2023-10-05-Cplusplus教学\u002F0300-数据类型与数据存放","数据类型与数据存放",[7],"0300",{"path":4645,"stem":4646,"title":4647,"authors":4648,"date":4613,"chapterOrder":4649,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0400-shu-ru-shu-chu","wiki\u002F2023-10-05-Cplusplus教学\u002F0400-输入输出","输入输出",[7],"0400",{"path":4651,"stem":4652,"title":4653,"authors":4654,"date":4613,"chapterOrder":4655,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0500-yun-suan-fu","wiki\u002F2023-10-05-Cplusplus教学\u002F0500-运算符","运算符",[7],"0500",{"path":4657,"stem":4658,"title":4659,"authors":4660,"date":4613,"chapterOrder":4661,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0600-cheng-xu-liu-cheng-jie-gou","wiki\u002F2023-10-05-Cplusplus教学\u002F0600-程序流程结构","程序流程结构",[7],"0600",{"path":4663,"stem":4664,"title":4665,"authors":4666,"date":4613,"chapterOrder":4667,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0700-shu-zu","wiki\u002F2023-10-05-Cplusplus教学\u002F0700-数组","数组",[7],"0700",{"path":4669,"stem":4670,"title":4671,"authors":4672,"date":4613,"chapterOrder":4673,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0800-han-shu-yu-tou-wen-jian","wiki\u002F2023-10-05-Cplusplus教学\u002F0800-函数与头文件","函数与头文件",[7],"0800",{"path":4675,"stem":4676,"title":4677,"authors":4678,"date":4613,"chapterOrder":4679,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0900-zhi-zhen","wiki\u002F2023-10-05-Cplusplus教学\u002F0900-指针","指针",[7],"0900",{"path":4681,"stem":4682,"title":4683,"authors":4684,"date":4613,"chapterOrder":4685,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1000-jie-gou-ti-yu-gong-yong-ti","wiki\u002F2023-10-05-Cplusplus教学\u002F1000-结构体与共用体","结构体与共用体",[7],"1000",{"path":4687,"stem":4688,"title":4689,"authors":4690,"date":4613,"chapterOrder":4691,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1100-nei-cun-fen-qu-yu-sheng-ming-zhou-qi","wiki\u002F2023-10-05-Cplusplus教学\u002F1100-内存分区与生命周期","内存分区与生命周期",[7],"1100",{"path":4693,"stem":4694,"title":4695,"authors":4696,"date":4613,"chapterOrder":4697,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1200-yin-yong","wiki\u002F2023-10-05-Cplusplus教学\u002F1200-引用","引用",[7],"1200",{"path":4699,"stem":4700,"title":4701,"authors":4702,"date":4613,"chapterOrder":4703,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1300-han-shu-ti-gao","wiki\u002F2023-10-05-Cplusplus教学\u002F1300-函数提高","函数提高",[7],"1300",{"path":4705,"stem":4706,"title":4707,"authors":4708,"date":4613,"chapterOrder":4709,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1350-ming-ming-kong-jian","wiki\u002F2023-10-05-Cplusplus教学\u002F1350-命名空间","命名空间",[7],"1350",{"path":4711,"stem":4712,"title":4713,"authors":4714,"date":4613,"chapterOrder":4715,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-0100-feng-zhuang","wiki\u002F2023-10-05-Cplusplus教学\u002F1400-0100-封装","封装",[7],"1400-0100",{"path":4717,"stem":4718,"title":4719,"authors":4720,"date":4613,"chapterOrder":4721,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-0200-dui-xiang-chu-shi-hua-he-qing-li","wiki\u002F2023-10-05-Cplusplus教学\u002F1400-0200-对象初始化和清理","对象初始化和清理",[7],"1400-0200",{"path":4723,"stem":4724,"title":4725,"authors":4726,"date":4613,"chapterOrder":4727,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-0300-dui-xiang-mo-xing-yu-this-zhi-zhen","wiki\u002F2023-10-05-Cplusplus教学\u002F1400-0300-对象模型与this指针","对象模型与this指针",[7],"1400-0300",{"path":4729,"stem":4730,"title":4731,"authors":4732,"date":4613,"chapterOrder":4733,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-0400-you-yuan-yu-yun-suan-fu-zhong-zai","wiki\u002F2023-10-05-Cplusplus教学\u002F1400-0400-友元与运算符重载","友元与运算符重载",[7],"1400-0400",{"path":4735,"stem":4736,"title":4737,"authors":4738,"date":4613,"chapterOrder":4739,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-0500-ji-cheng","wiki\u002F2023-10-05-Cplusplus教学\u002F1400-0500-继承","继承",[7],"1400-0500",{"path":4741,"stem":4742,"title":4743,"authors":4744,"date":4613,"chapterOrder":4745,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-0600-duo-tai","wiki\u002F2023-10-05-Cplusplus教学\u002F1400-0600-多态","多态",[7],"1400-0600",{"path":4747,"stem":4748,"title":4749,"authors":4750,"date":4613,"chapterOrder":4751,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-lei-he-dui-xiang","wiki\u002F2023-10-05-Cplusplus教学\u002F1400-类和对象","类和对象",[7],"1400",{"path":4753,"stem":4754,"title":4755,"authors":4756,"date":4613,"chapterOrder":4757,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1450-han-shu-zhi-zhen","wiki\u002F2023-10-05-Cplusplus教学\u002F1450-函数指针","函数指针",[7],"1450",{"path":4759,"stem":4760,"title":4761,"authors":4762,"date":4613,"chapterOrder":4763,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1500-wen-jian-cao-zuo","wiki\u002F2023-10-05-Cplusplus教学\u002F1500-文件操作","文件操作",[7],"1500",{"path":4765,"stem":4766,"title":4767,"authors":4768,"date":4613,"chapterOrder":4769,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1600-yi-chang-chu-li-yu-cuo-wu-ma","wiki\u002F2023-10-05-Cplusplus教学\u002F1600-异常处理与错误码","异常处理",[7],"1600",{"path":4771,"stem":4772,"title":4773,"authors":4774,"date":4613,"chapterOrder":4775,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1700-mu-ban","wiki\u002F2023-10-05-Cplusplus教学\u002F1700-模板","模板",[7],"1700",{"path":4777,"stem":4778,"title":4779,"authors":4780,"date":4613,"chapterOrder":4781,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0100-stl-chu-shi","wiki\u002F2023-10-05-Cplusplus教学\u002F1800-0100-STL初识","STL初识",[7],"1800-0100",{"path":4783,"stem":4784,"title":4785,"authors":4786,"date":4613,"chapterOrder":4787,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0200-std-array","wiki\u002F2023-10-05-Cplusplus教学\u002F1800-0200-std-array","std::array",[7],"1800-0200",{"path":4789,"stem":4790,"title":4791,"authors":4792,"date":4613,"chapterOrder":4793,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0300-string-rong-qi","wiki\u002F2023-10-05-Cplusplus教学\u002F1800-0300-string容器","string容器",[7],"1800-0300",{"path":4795,"stem":4796,"title":4797,"authors":4798,"date":4613,"chapterOrder":4799,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0400-vector-rong-qi","wiki\u002F2023-10-05-Cplusplus教学\u002F1800-0400-vector容器","vector 容器",[7],"1800-0400",{"path":4801,"stem":4802,"title":4803,"authors":4804,"date":4613,"chapterOrder":4805,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0500-deque-rong-qi","wiki\u002F2023-10-05-Cplusplus教学\u002F1800-0500-deque容器","deque 容器",[7],"1800-0500",{"path":4807,"stem":4808,"title":4809,"authors":4810,"date":4613,"chapterOrder":4811,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0600-stack-rong-qi","wiki\u002F2023-10-05-Cplusplus教学\u002F1800-0600-stack容器","stack 容器",[7],"1800-0600",{"path":4813,"stem":4814,"title":4815,"authors":4816,"date":4613,"chapterOrder":4817,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0700-queue-rong-qi","wiki\u002F2023-10-05-Cplusplus教学\u002F1800-0700-queue容器","queue 容器",[7],"1800-0700",{"path":4819,"stem":4820,"title":4821,"authors":4822,"date":4613,"chapterOrder":4823,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0800-list-rong-qi","wiki\u002F2023-10-05-Cplusplus教学\u002F1800-0800-list容器","list 容器",[7],"1800-0800",{"path":4825,"stem":4826,"title":4827,"authors":4828,"date":4613,"chapterOrder":4829,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0900-set-rong-qi","wiki\u002F2023-10-05-Cplusplus教学\u002F1800-0900-set容器","set \u002F multiset 容器",[7],"1800-0900",{"path":4831,"stem":4832,"title":4833,"authors":4834,"date":4613,"chapterOrder":4835,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-1000-map-rong-qi","wiki\u002F2023-10-05-Cplusplus教学\u002F1800-1000-map容器","map \u002F multimap 容器",[7],"1800-1000",{"path":4837,"stem":4838,"title":4839,"authors":4840,"date":4613,"chapterOrder":4841,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-1100-han-shu-dui-xiang-yu-wei-ci","wiki\u002F2023-10-05-Cplusplus教学\u002F1800-1100-函数对象与谓词","函数对象与谓词",[7],"1800-1100",{"path":4843,"stem":4844,"title":4845,"authors":4846,"date":4613,"chapterOrder":4847,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-1200-chang-yong-suan-fa","wiki\u002F2023-10-05-Cplusplus教学\u002F1800-1200-常用算法","常用算法",[7],"1800-1200",{"path":4849,"stem":4850,"title":4851,"authors":4852,"date":4613,"chapterOrder":4853,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-stl-ti-gao-bian-cheng","wiki\u002F2023-10-05-Cplusplus教学\u002F1800-STL提高编程","STL提高编程",[7],"1800",{"path":4855,"stem":4856,"title":4857,"authors":4858,"date":4613,"chapterOrder":4859,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1900-c-lei-xing-zhuan-huan","wiki\u002F2023-10-05-Cplusplus教学\u002F1900-C++类型转换","C++类型转换",[7],"1900",{"path":4861,"stem":4862,"title":4863,"authors":4864,"date":4613,"chapterOrder":4865,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0100-auto","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-0100-auto","auto",[7],"2000-0100",{"path":4867,"stem":4868,"title":4869,"authors":4870,"date":4613,"chapterOrder":4871,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0200-nullptr","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-0200-nullptr","nullptr",[7],"2000-0200",{"path":4873,"stem":4874,"title":782,"authors":4875,"date":4613,"chapterOrder":4876,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0300-using","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-0300-using",[7],"2000-0300",{"path":4878,"stem":4879,"title":4880,"authors":4881,"date":4613,"chapterOrder":4882,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0400-enum-class","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-0400-enum-class","enum class",[7],"2000-0400",{"path":4884,"stem":4885,"title":4886,"authors":4887,"date":4613,"chapterOrder":4888,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0500-fan-wei-for-xun-huan","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-0500-范围for循环","范围 for 循环",[7],"2000-0500",{"path":4890,"stem":4891,"title":4892,"authors":4893,"date":4613,"chapterOrder":4894,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0600-jie-gou-hua-bang-ding","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-0600-结构化绑定","结构化绑定",[7],"2000-0600",{"path":4896,"stem":4897,"title":4898,"authors":4899,"date":4613,"chapterOrder":4900,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0700-constexpr","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-0700-constexpr","constexpr",[7],"2000-0700",{"path":4902,"stem":4903,"title":4904,"authors":4905,"date":4613,"chapterOrder":4906,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0800-raii","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-0800-RAII","RAII",[7],"2000-0800",{"path":4908,"stem":4909,"title":4910,"authors":4911,"date":4613,"chapterOrder":4912,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0900-zhi-neng-zhi-zhen","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-0900-智能指针","智能指针",[7],"2000-0900",{"path":4914,"stem":4915,"title":4916,"authors":4917,"date":4613,"chapterOrder":4918,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1000-you-zhi-yin-yong-he-yi-dong-yu-yi","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1000-右值引用和移动语义","右值引用和移动语义",[7],"2000-1000",{"path":4920,"stem":4921,"title":4922,"authors":4923,"date":4613,"chapterOrder":4924,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1100-lambda-biao-da-shi","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1100-Lambda表达式","Lambda 表达式",[7],"2000-1100",{"path":4926,"stem":4927,"title":4928,"authors":4929,"date":4613,"chapterOrder":4930,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1200-std-function","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1200-std-function","std::function",[7],"2000-1200",{"path":4932,"stem":4933,"title":4934,"authors":4935,"date":4613,"chapterOrder":4936,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1300-std-bind","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1300-std-bind","std::bind",[7],"2000-1300",{"path":4938,"stem":4939,"title":4940,"authors":4941,"date":4613,"chapterOrder":4942,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1400-std-optional","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1400-std-optional","std::optional",[7],"2000-1400",{"path":4944,"stem":4945,"title":4946,"authors":4947,"date":4613,"chapterOrder":4948,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1500-std-variant","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1500-std-variant","std::variant",[7],"2000-1500",{"path":4950,"stem":4951,"title":4952,"authors":4953,"date":4613,"chapterOrder":4954,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1600-std-span","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1600-std-span","std::span",[7],"2000-1600",{"path":4956,"stem":4957,"title":4958,"authors":4959,"date":4613,"chapterOrder":4960,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1700-std-format-print","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1700-std-format-print","std::format \u002F std::print",[7],"2000-1700",{"path":4962,"stem":4963,"title":4964,"authors":4965,"date":4613,"chapterOrder":4966,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1800-std-chrono","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1800-std-chrono","std::chrono",[7],"2000-1800",{"path":4968,"stem":4969,"title":4970,"authors":4971,"date":4613,"chapterOrder":4972,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-0100-bing-fa-shi-shen-me","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-0100-并发是什么","并发是什么",[7],"2000-1900-0100",{"path":4974,"stem":4975,"title":4976,"authors":4977,"date":4613,"chapterOrder":4978,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-0200-bing-xing-shi-shen-me","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-0200-并行是什么","并行是什么",[7],"2000-1900-0200",{"path":4980,"stem":4981,"title":4982,"authors":4983,"date":4613,"chapterOrder":4984,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-0300-xie-cheng-shi-shen-me","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-0300-协程是什么","协程是什么",[7],"2000-1900-0300",{"path":4986,"stem":4987,"title":4988,"authors":4989,"date":4613,"chapterOrder":4990,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-1000-bing-fa-bian-cheng","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-1000-并发编程","并发编程",[7],"2000-1900-1000",{"path":4992,"stem":4993,"title":51,"authors":4994,"date":4613,"chapterOrder":4995,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-1100-std-thread","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-1100-std-thread",[7],"2000-1900-1100",{"path":4997,"stem":4998,"title":4999,"authors":5000,"date":4613,"chapterOrder":5001,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-1200-mutex-lock-guard","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-1200-mutex-lock-guard","mutex 与 RAII 锁",[7],"2000-1900-1200",{"path":5003,"stem":5004,"title":5005,"authors":5006,"date":4613,"chapterOrder":5007,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-1300-std-atomic","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-1300-std-atomic","std::atomic",[7],"2000-1900-1300",{"path":5009,"stem":5010,"title":5011,"authors":5012,"date":4613,"chapterOrder":5013,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-1400-condition-variable","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-1400-condition-variable","condition_variable",[7],"2000-1900-1400",{"path":5015,"stem":5016,"title":5017,"authors":5018,"date":4613,"chapterOrder":5019,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-1500-future-async-promise","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-1500-future-async-promise","future、async、promise 与 packaged_task",[7],"2000-1900-1500",{"path":4620,"stem":4622,"title":5,"authors":5021,"date":4613,"chapterOrder":4612,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},[7],{"path":5023,"stem":5024,"title":5025,"authors":5026,"date":4613,"chapterOrder":5027,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-1700-semaphore-latch-barrier","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-1700-semaphore-latch-barrier","semaphore、latch 与 barrier",[7],"2000-1900-1700",{"path":5029,"stem":5030,"title":5031,"authors":5032,"date":4613,"chapterOrder":5033,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-bing-fa-bing-xing-yu-xie-cheng","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-并发并行与协程","并发、并行与协程",[7],"2000-1900",{"path":5035,"stem":5036,"title":5037,"authors":5038,"date":4613,"chapterOrder":5039,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-2000-std-filesystem","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-2000-std-filesystem","std::filesystem",[7],"2000-2000",{"path":5041,"stem":5042,"title":5043,"authors":5044,"date":4613,"chapterOrder":5045,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-2100-modules-jian-jie","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-2100-modules简介","modules 简介",[7],"2000-2100",{"path":5047,"stem":5048,"title":5049,"authors":5050,"date":4613,"chapterOrder":5051,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-xian-dai-c","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-现代C++","现代C++",[7],"2000",{"path":5053,"stem":5054,"title":5055,"authors":5056,"date":4613,"chapterOrder":5057,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0100-ding-shi-qi-yu-yi-bu-io","wiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0100-定时器与异步IO","定时器与异步 IO",[7],"2100-0100-0100",{"path":5059,"stem":5060,"title":5061,"authors":5062,"date":4613,"chapterOrder":5063,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0200-boost-asio-ji-chu","wiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0200-Boost.Asio基础","Boost.Asio 基础",[7],"2100-0100-0200",{"path":5065,"stem":5066,"title":5067,"authors":5068,"date":4613,"chapterOrder":5069,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0300-chuan-kou-tong-xin","wiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0300-串口通信","串口通信教学",[7],"2100-0100-0300",{"path":5071,"stem":5072,"title":5073,"authors":5074,"date":4613,"chapterOrder":5075,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0350-chuan-kou-tong-xin-chuan-kou-bao-xie-yi-shi-li","wiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0350-串口通信串口包协议实例","串口通信串口包协议实例",[7],"2100-0100-0350",{"path":5077,"stem":5078,"title":5079,"authors":5080,"date":4613,"chapterOrder":5081,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0400-tcp-tong-xin","wiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0400-TCP通信","TCP 通信",[7],"2100-0100-0400",{"path":5083,"stem":5084,"title":5085,"authors":5086,"date":4613,"chapterOrder":5087,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0500-udp-tong-xin","wiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0500-UDP通信","UDP 通信",[7],"2100-0100-0500",{"path":5089,"stem":5090,"title":5091,"authors":5092,"date":4613,"chapterOrder":5093,"chapterDepth":208,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0600-ji-qi-ren-gong-cheng-xie-fa-yu-ros2-ji-cheng","wiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0600-机器人工程写法与ROS2集成","机器人工程写法与 ROS2 集成",[7],"2100-0100-0600",{"path":5095,"stem":5096,"title":5097,"authors":5098,"date":4613,"chapterOrder":5099,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-boost-asio-yi-bu-io-ku","wiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-Boost.Asio异步IO库","Boost.Asio异步IO库",[7],"2100-0100",{"path":5101,"stem":5102,"title":5103,"authors":5104,"date":4613,"chapterOrder":5105,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0200-eigen-xian-xing-dai-shu-ku","wiki\u002F2023-10-05-Cplusplus教学\u002F2100-0200-Eigen线性代数库","Eigen线性代数库",[7],"2100-0200",{"path":5107,"stem":5108,"title":5109,"authors":5110,"date":4613,"chapterOrder":5111,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0300-opencv-ji-suan-ji-shi-jue-ku","wiki\u002F2023-10-05-Cplusplus教学\u002F2100-0300-OpenCV计算机视觉库","OpenCV计算机视觉库",[7],"2100-0300",{"path":5113,"stem":5114,"title":5115,"authors":5116,"date":4613,"chapterOrder":5117,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0400-pcl-dian-yun-ku","wiki\u002F2023-10-05-Cplusplus教学\u002F2100-0400-PCL点云库","PCL点云库",[7],"2100-0400",{"path":5119,"stem":5120,"title":5121,"authors":5122,"date":4613,"chapterOrder":5123,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0500-sophus-li-qun-li-dai-shu-ku","wiki\u002F2023-10-05-Cplusplus教学\u002F2100-0500-Sophus李群李代数库","Sophus 李群李代数库",[7],"2100-0500",{"path":5125,"stem":5126,"title":5127,"authors":5128,"date":4613,"chapterOrder":5129,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-chang-yong-ku","wiki\u002F2023-10-05-Cplusplus教学\u002F2100-常用库","常用库学习",[7],"2100",{"path":5131,"stem":5132,"title":5133,"authors":5134,"date":4613,"chapterOrder":5135,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2200-0100-cmakepresets-yu-gou-jian-an-zhuang","wiki\u002F2023-10-05-Cplusplus教学\u002F2200-0100-CMakePresets与构建安装","CMakePresets与构建安装",[7],"2200-0100",{"path":5137,"stem":5138,"title":5139,"authors":5140,"date":4613,"chapterOrder":5141,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2200-0200-ding-ceng-cmake-yu-gong-gong-bian-yi-xuan-xiang","wiki\u002F2023-10-05-Cplusplus教学\u002F2200-0200-顶层CMake与公共编译选项","顶层CMake与公共编译选项",[7],"2200-0200",{"path":5143,"stem":5144,"title":5145,"authors":5146,"date":4613,"chapterOrder":5147,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2200-0300-src-yu-lib-mo-kuai-cmake-xiang-jie","wiki\u002F2023-10-05-Cplusplus教学\u002F2200-0300-src与lib模块CMake详解","src与lib模块CMake详解",[7],"2200-0300",{"path":5149,"stem":5150,"title":5151,"authors":5152,"date":4613,"chapterOrder":5153,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2200-0400-di-san-fang-ku-yi-lai-xie-fa","wiki\u002F2023-10-05-Cplusplus教学\u002F2200-0400-第三方库依赖写法","第三方库依赖写法",[7],"2200-0400",{"path":5155,"stem":5156,"title":5157,"authors":5158,"date":4613,"chapterOrder":5159,"chapterDepth":29,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2200-0500-mu-ban-kuo-zhan-yu-chang-jian-wen-ti","wiki\u002F2023-10-05-Cplusplus教学\u002F2200-0500-模板扩展与常见问题","模板扩展与常见问题",[7],"2200-0500",{"path":5161,"stem":5162,"title":5163,"authors":5164,"date":4613,"chapterOrder":5165,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":4618},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2200-cmake-gong-cheng-mu-ban","wiki\u002F2023-10-05-Cplusplus教学\u002F2200-CMake工程模板","CMake工程模板",[7],"2200",{"path":4615,"stem":5167,"title":5168,"authors":5169,"date":4613,"chapterOrder":5170,"chapterDepth":4631,"docKey":4614,"docRoot":4615,"docTitle":4616,"isWikiDoc":219,"isWikiIndex":219},"wiki\u002F2023-10-05-Cplusplus教学\u002Findex","C\u002FC++教程",[7],null,[5172,5174,5177,5180],{"name":7,"image":5173},"\u002Fimages\u002Fmember_photo\u002F董佳辉.jpg",{"name":5175,"image":5176},"宫金良","\u002Fimages\u002Fmember_photo\u002F宫金良.jpg",{"name":5178,"image":5179},"巩丽","\u002Fimages\u002Fmember_photo\u002F巩丽.png",{"name":5181,"image":5182},"张彦斐","\u002Fimages\u002Fmember_photo\u002F张彦斐.jpg",1792431899261]