[{"data":1,"prerenderedAt":7826},["ShallowReactive",2],{"wiki-page-\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0100-ding-shi-qi-yu-yi-bu-io":3,"wiki-doc-items-2023-10-05-cplusplus-jiao-xue":7267,"wiki:author-members":7814},{"id":4,"title":5,"authors":6,"body":8,"chapterDepth":80,"chapterOrder":7255,"date":7256,"description":62,"docKey":7257,"docRoot":7258,"docTitle":7259,"extension":7260,"isWikiDoc":99,"isWikiIndex":7261,"meta":7262,"navigation":99,"path":7263,"seo":7264,"stem":7265,"wikiDepth":69,"__hash__":7266},"wiki\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0100-定时器与异步IO.md","定时器与异步 IO",[7],"董佳辉",{"type":9,"value":10,"toc":7173},"minimark",[11,27,34,37,46,50,53,56,292,299,302,310,313,319,322,328,331,338,341,355,358,361,368,371,378,384,387,390,399,406,430,433,439,442,449,452,454,461,464,467,495,498,878,882,885,888,894,897,911,914,920,922,928,931,939,942,954,960,966,972,975,1004,1007,1013,1019,1050,1053,1059,1062,1065,1069,1072,1077,1080,1086,1092,1094,1101,1104,1107,1132,1135,1615,1619,1622,1624,1630,1633,1639,1642,1648,1650,1656,1659,1662,1674,1677,1683,1690,1696,1699,1736,1739,1745,1751,1756,1758,1765,1768,1771,1774,1780,1783,2299,2303,2306,2308,2314,2317,2323,2326,2332,2334,2340,2343,2353,2356,2362,2365,2432,2435,2441,2447,2450,2456,2466,2469,2472,2491,2498,2501,2507,2510,2512,2516,2519,2522,2525,2531,2534,2967,2971,2974,2976,2982,2985,2991,2993,2999,3002,3005,3066,3069,3074,3083,3086,3088,3134,3137,3143,3150,3156,3162,3170,3173,3176,3200,3205,3211,3241,3247,3249,3253,3256,3259,3276,3279,3881,3885,3888,3890,3896,3898,3904,3907,3913,3915,3921,3924,3931,3934,3946,3949,3951,3957,3960,3966,3969,3975,3978,4597,4601,4604,4607,4613,4616,4622,4625,4628,4635,4641,4650,4659,4661,4704,4707,4727,4730,4732,4740,4743,4746,4758,4764,4767,4779,4782,4788,4793,4796,4802,4805,4817,4820,4826,4829,4832,4841,4848,4851,4861,4864,4870,4873,4879,4881,4884,5829,5831,5838,5841,5861,5864,5975,5978,5983,5986,5992,5995,6001,6004,6016,6019,6029,6034,6037,6039,6046,6049,6073,6076,6086,6089,6098,6100,6129,6132,6138,6144,6150,6153,6156,6162,6165,6171,6174,6177,6183,6186,6192,6195,6201,6203,6209,6215,6220,6226,6229,6235,6238,6244,6247,6250,6256,6259,6265,6268,6275,6277,6281,6286,6292,6295,6307,6310,6313,6319,6322,6328,6331,6337,6343,6345,6353,6356,6366,6369,6380,6383,6389,6395,6398,6406,6409,6412,6422,6425,6428,6469,6472,6478,6481,6483,6487,6490,6493,6501,6504,6510,6513,6520,6523,6529,6532,6541,6544,6547,6555,6561,6569,6572,6574,6580,6583,6586,6593,6595,6602,6604,6630,6632,6641,6643,6717,6720,6726,6729,6735,6737,6749,6752,6762,6764,6767,6770,6776,6779,6793,6796,6798,6804,6807,6810,6816,6819,6825,6828,6831,6837,6840,6846,6849,6856,6858,6867,6870,6881,6884,6929,6932,6935,6941,6943,6949,6952,6958,6961,6963,6969,6972,6977,6980,6983,6985,6988,6994,7006,7009,7012,7018,7021,7027,7030,7038,7041,7044,7050,7053,7059,7062,7071,7074,7077,7117,7169],[12,13,14],"blockquote",{},[15,16,17,18,21,22,26],"p",{},"本节是整套 Boost.Asio 教程最重要的一节。",[19,20],"br",{},"\n串口、TCP、UDP 的异步模型都和定时器类似：先注册异步操作，然后由 ",[23,24,25],"code",{},"io_context.run()"," 驱动回调执行。",[15,28,29,30,33],{},"本节所有异步回调都使用 ",[23,31,32],{},"std::bind","，暂时不使用 lambda。",[35,36],"hr",{},[38,39,41,42,45],"h2",{"id":40},"示例-1普通-main-里写同步定时器","示例 1：普通 ",[23,43,44],{},"main()"," 里写同步定时器",[47,48,49],"h3",{"id":49},"程序目标",[15,51,52],{},"先写最简单的阻塞式定时器：程序启动后立刻打印一句话，然后阻塞等待 2 秒，再打印结束。",[47,54,55],{"id":55},"完整代码",[57,58,63],"pre",{"className":59,"code":60,"language":61,"meta":62,"style":62},"language-cpp shiki shiki-themes github-light github-dark","#include \u003Cboost\u002Fasio.hpp>\n#include \u003Cchrono>\n#include \u003Cprint>\n\nint main()\n{\n    \u002F\u002F 程序从 main 函数开始执行，下面的语句会按顺序运行。\n    \u002F\u002F io_context 是 Asio 的事件循环对象，异步任务需要靠它调度。\n    boost::asio::io_context io;\n\n    \u002F\u002F 创建定时器，并设置到期时间。\n    boost::asio::steady_timer timer(io, std::chrono::seconds(2));\n\n    std::println(\"程序开始：准备等待 2 秒\");\n\n    \u002F\u002F 同步等待会阻塞当前线程，时间没到之前不会继续往下执行。\n    timer.wait();\n\n    std::println(\"2 秒到了：timer.wait() 返回\");\n\n    return 0;\n}\n","cpp","",[23,64,65,78,86,94,101,115,121,128,134,149,154,160,201,206,225,230,236,248,253,269,274,286],{"__ignoreMap":62},[66,67,70,74],"span",{"class":68,"line":69},"line",1,[66,71,73],{"class":72},"szBVR","#include",[66,75,77],{"class":76},"sZZnC"," \u003Cboost\u002Fasio.hpp>\n",[66,79,81,83],{"class":68,"line":80},2,[66,82,73],{"class":72},[66,84,85],{"class":76}," \u003Cchrono>\n",[66,87,89,91],{"class":68,"line":88},3,[66,90,73],{"class":72},[66,92,93],{"class":76}," \u003Cprint>\n",[66,95,97],{"class":68,"line":96},4,[66,98,100],{"emptyLinePlaceholder":99},true,"\n",[66,102,104,107,111],{"class":68,"line":103},5,[66,105,106],{"class":72},"int",[66,108,110],{"class":109},"sScJk"," main",[66,112,114],{"class":113},"sVt8B","()\n",[66,116,118],{"class":68,"line":117},6,[66,119,120],{"class":113},"{\n",[66,122,124],{"class":68,"line":123},7,[66,125,127],{"class":126},"sJ8bj","    \u002F\u002F 程序从 main 函数开始执行，下面的语句会按顺序运行。\n",[66,129,131],{"class":68,"line":130},8,[66,132,133],{"class":126},"    \u002F\u002F io_context 是 Asio 的事件循环对象，异步任务需要靠它调度。\n",[66,135,137,140,143,146],{"class":68,"line":136},9,[66,138,139],{"class":109},"    boost",[66,141,142],{"class":113},"::",[66,144,145],{"class":109},"asio",[66,147,148],{"class":113},"::io_context io;\n",[66,150,152],{"class":68,"line":151},10,[66,153,100],{"emptyLinePlaceholder":99},[66,155,157],{"class":68,"line":156},11,[66,158,159],{"class":126},"    \u002F\u002F 创建定时器，并设置到期时间。\n",[66,161,163,165,167,169,172,175,178,181,183,186,188,191,194,198],{"class":68,"line":162},12,[66,164,139],{"class":109},[66,166,142],{"class":113},[66,168,145],{"class":109},[66,170,171],{"class":113},"::steady_timer ",[66,173,174],{"class":109},"timer",[66,176,177],{"class":113},"(io, ",[66,179,180],{"class":109},"std",[66,182,142],{"class":113},[66,184,185],{"class":109},"chrono",[66,187,142],{"class":113},[66,189,190],{"class":109},"seconds",[66,192,193],{"class":113},"(",[66,195,197],{"class":196},"sj4cs","2",[66,199,200],{"class":113},"));\n",[66,202,204],{"class":68,"line":203},13,[66,205,100],{"emptyLinePlaceholder":99},[66,207,209,212,214,217,219,222],{"class":68,"line":208},14,[66,210,211],{"class":109},"    std",[66,213,142],{"class":113},[66,215,216],{"class":109},"println",[66,218,193],{"class":113},[66,220,221],{"class":76},"\"程序开始：准备等待 2 秒\"",[66,223,224],{"class":113},");\n",[66,226,228],{"class":68,"line":227},15,[66,229,100],{"emptyLinePlaceholder":99},[66,231,233],{"class":68,"line":232},16,[66,234,235],{"class":126},"    \u002F\u002F 同步等待会阻塞当前线程，时间没到之前不会继续往下执行。\n",[66,237,239,242,245],{"class":68,"line":238},17,[66,240,241],{"class":113},"    timer.",[66,243,244],{"class":109},"wait",[66,246,247],{"class":113},"();\n",[66,249,251],{"class":68,"line":250},18,[66,252,100],{"emptyLinePlaceholder":99},[66,254,256,258,260,262,264,267],{"class":68,"line":255},19,[66,257,211],{"class":109},[66,259,142],{"class":113},[66,261,216],{"class":109},[66,263,193],{"class":113},[66,265,266],{"class":76},"\"2 秒到了：timer.wait() 返回\"",[66,268,224],{"class":113},[66,270,272],{"class":68,"line":271},20,[66,273,100],{"emptyLinePlaceholder":99},[66,275,277,280,283],{"class":68,"line":276},21,[66,278,279],{"class":72},"    return",[66,281,282],{"class":196}," 0",[66,284,285],{"class":113},";\n",[66,287,289],{"class":68,"line":288},22,[66,290,291],{"class":113},"}\n",[15,293,294,298],{},[295,296,297],"strong",{},"运行结果","：见下方“运行输出与时间顺序”；如果示例涉及定时器、线程、网络或外部设备，具体时间和顺序可能会随环境略有变化。",[47,300,301],{"id":301},"运行输出与时间顺序",[57,303,308],{"className":304,"code":306,"language":307,"meta":62},[305],"language-text","程序开始：准备等待 2 秒\n","text",[23,309,306],{"__ignoreMap":62},[15,311,312],{},"等待约 2 秒后：",[57,314,317],{"className":315,"code":316,"language":307,"meta":62},[305],"2 秒到了：timer.wait() 返回\n",[23,318,316],{"__ignoreMap":62},[15,320,321],{},"完整输出类似：",[57,323,326],{"className":324,"code":325,"language":307,"meta":62},[305],"程序开始：准备等待 2 秒\n2 秒到了：timer.wait() 返回\n",[23,327,325],{"__ignoreMap":62},[47,329,330],{"id":330},"本示例需要注意的点",[15,332,333,334,337],{},"这个程序没有体现“异步”，因为 ",[23,335,336],{},"timer.wait()"," 会直接阻塞当前线程。",[15,339,340],{},"也就是说，程序卡在这里：",[57,342,344],{"className":59,"code":343,"language":61,"meta":62,"style":62},"timer.wait();\n",[23,345,346],{"__ignoreMap":62},[66,347,348,351,353],{"class":68,"line":69},[66,349,350],{"class":113},"timer.",[66,352,244],{"class":109},[66,354,247],{"class":113},[15,356,357],{},"2 秒没有到之前，下一行不会执行。",[47,359,360],{"id":360},"关键函数说明",[362,363,365],"h4",{"id":364},"boostasioio_context-io",[23,366,367],{},"boost::asio::io_context io;",[15,369,370],{},"作用：创建一个 Asio 事件循环对象。",[15,372,373,374,377],{},"在同步 ",[23,375,376],{},"wait()"," 示例中，它看起来没什么存在感；但到了异步版本，所有异步事件都要靠它驱动。",[362,379,381],{"id":380},"boostasiosteady_timer-timerio-stdchronoseconds2",[23,382,383],{},"boost::asio::steady_timer timer(io, std::chrono::seconds(2));",[15,385,386],{},"作用：创建一个基于稳定时钟的定时器，设置 2 秒后到期。",[15,388,389],{},"参数：",[57,391,393],{"className":59,"code":392,"language":61,"meta":62,"style":62},"io\n",[23,394,395],{"__ignoreMap":62},[66,396,397],{"class":68,"line":69},[66,398,392],{"class":113},[15,400,401,402,405],{},"表示这个 timer 归哪个 ",[23,403,404],{},"io_context"," 管。",[57,407,409],{"className":59,"code":408,"language":61,"meta":62,"style":62},"std::chrono::seconds(2)\n",[23,410,411],{"__ignoreMap":62},[66,412,413,415,417,419,421,423,425,427],{"class":68,"line":69},[66,414,180],{"class":109},[66,416,142],{"class":113},[66,418,185],{"class":109},[66,420,142],{"class":113},[66,422,190],{"class":109},[66,424,193],{"class":113},[66,426,197],{"class":196},[66,428,429],{"class":113},")\n",[15,431,432],{},"表示相对当前时间 2 秒后到期。",[362,434,436],{"id":435},"timerwait",[23,437,438],{},"timer.wait();",[15,440,441],{},"作用：阻塞等待 timer 到期。",[15,443,444,445,448],{},"返回值：",[23,446,447],{},"void","。",[15,450,451],{},"特点：简单，但是会阻塞当前线程。机器人程序里如果在主控制循环里这么写，很容易卡住整个程序。",[35,453],{},[38,455,457,458,460],{"id":456},"示例-2普通-main-里写异步定时器","示例 2：普通 ",[23,459,44],{}," 里写异步定时器",[47,462,49],{"id":463},"程序目标-1",[15,465,466],{},"把示例 1 改成异步写法：",[468,469,470,474,480,486,489],"ol",{},[471,472,473],"li",{},"注册一个 2 秒定时器；",[471,475,476,479],{},[23,477,478],{},"async_wait()"," 不阻塞；",[471,481,482,485],{},[23,483,484],{},"io.run()"," 开始阻塞；",[471,487,488],{},"2 秒后回调函数被执行；",[471,490,491,492,494],{},"没有任务后 ",[23,493,484],{}," 返回。",[47,496,55],{"id":497},"完整代码-1",[57,499,501],{"className":59,"code":500,"language":61,"meta":62,"style":62},"#include \u003Cboost\u002Fasio.hpp>\n#include \u003Cboost\u002Fsystem\u002Ferror_code.hpp>\n#include \u003Cchrono>\n#include \u003Cfunctional>\n#include \u003Cprint>\n\nvoid on_timer(const boost::system::error_code& ec)\n{\n    if (ec)\n    {\n        std::println(\"定时器被取消，错误信息：{}\", ec.message());\n        return;\n    }\n\n    std::println(\"回调函数 on_timer：2 秒到了\");\n}\n\nint main()\n{\n    \u002F\u002F 程序从 main 函数开始执行，下面的语句会按顺序运行。\n    \u002F\u002F io_context 是 Asio 的事件循环对象，异步任务需要靠它调度。\n    boost::asio::io_context io;\n\n    \u002F\u002F 创建定时器，并设置到期时间。\n    boost::asio::steady_timer timer(io, std::chrono::seconds(2));\n\n    std::println(\"main：注册 async_wait\");\n\n    \u002F\u002F 注册异步等待：这一行不会阻塞，回调会在定时器到期后执行。\n    timer.async_wait(std::bind(on_timer, std::placeholders::_1));\n\n    std::println(\"main：async_wait 已经返回，但回调还没执行\");\n    std::println(\"main：准备调用 io.run()\");\n\n    io.run();\n\n    std::println(\"main：io.run() 返回，程序结束\");\n\n    return 0;\n}\n",[23,502,503,509,516,522,529,535,539,573,577,585,590,613,620,625,629,644,648,652,660,664,668,672,682,687,692,723,728,744,749,755,785,790,806,822,827,838,843,859,864,873],{"__ignoreMap":62},[66,504,505,507],{"class":68,"line":69},[66,506,73],{"class":72},[66,508,77],{"class":76},[66,510,511,513],{"class":68,"line":80},[66,512,73],{"class":72},[66,514,515],{"class":76}," \u003Cboost\u002Fsystem\u002Ferror_code.hpp>\n",[66,517,518,520],{"class":68,"line":88},[66,519,73],{"class":72},[66,521,85],{"class":76},[66,523,524,526],{"class":68,"line":96},[66,525,73],{"class":72},[66,527,528],{"class":76}," \u003Cfunctional>\n",[66,530,531,533],{"class":68,"line":103},[66,532,73],{"class":72},[66,534,93],{"class":76},[66,536,537],{"class":68,"line":117},[66,538,100],{"emptyLinePlaceholder":99},[66,540,541,543,546,548,551,554,556,559,561,564,567,571],{"class":68,"line":123},[66,542,447],{"class":72},[66,544,545],{"class":109}," on_timer",[66,547,193],{"class":113},[66,549,550],{"class":72},"const",[66,552,553],{"class":109}," boost",[66,555,142],{"class":113},[66,557,558],{"class":109},"system",[66,560,142],{"class":113},[66,562,563],{"class":109},"error_code",[66,565,566],{"class":72},"&",[66,568,570],{"class":569},"s4XuR"," ec",[66,572,429],{"class":113},[66,574,575],{"class":68,"line":130},[66,576,120],{"class":113},[66,578,579,582],{"class":68,"line":136},[66,580,581],{"class":72},"    if",[66,583,584],{"class":113}," (ec)\n",[66,586,587],{"class":68,"line":151},[66,588,589],{"class":113},"    {\n",[66,591,592,595,597,599,601,604,607,610],{"class":68,"line":156},[66,593,594],{"class":109},"        std",[66,596,142],{"class":113},[66,598,216],{"class":109},[66,600,193],{"class":113},[66,602,603],{"class":76},"\"定时器被取消，错误信息：{}\"",[66,605,606],{"class":113},", ec.",[66,608,609],{"class":109},"message",[66,611,612],{"class":113},"());\n",[66,614,615,618],{"class":68,"line":162},[66,616,617],{"class":72},"        return",[66,619,285],{"class":113},[66,621,622],{"class":68,"line":203},[66,623,624],{"class":113},"    }\n",[66,626,627],{"class":68,"line":208},[66,628,100],{"emptyLinePlaceholder":99},[66,630,631,633,635,637,639,642],{"class":68,"line":227},[66,632,211],{"class":109},[66,634,142],{"class":113},[66,636,216],{"class":109},[66,638,193],{"class":113},[66,640,641],{"class":76},"\"回调函数 on_timer：2 秒到了\"",[66,643,224],{"class":113},[66,645,646],{"class":68,"line":232},[66,647,291],{"class":113},[66,649,650],{"class":68,"line":238},[66,651,100],{"emptyLinePlaceholder":99},[66,653,654,656,658],{"class":68,"line":250},[66,655,106],{"class":72},[66,657,110],{"class":109},[66,659,114],{"class":113},[66,661,662],{"class":68,"line":255},[66,663,120],{"class":113},[66,665,666],{"class":68,"line":271},[66,667,127],{"class":126},[66,669,670],{"class":68,"line":276},[66,671,133],{"class":126},[66,673,674,676,678,680],{"class":68,"line":288},[66,675,139],{"class":109},[66,677,142],{"class":113},[66,679,145],{"class":109},[66,681,148],{"class":113},[66,683,685],{"class":68,"line":684},23,[66,686,100],{"emptyLinePlaceholder":99},[66,688,690],{"class":68,"line":689},24,[66,691,159],{"class":126},[66,693,695,697,699,701,703,705,707,709,711,713,715,717,719,721],{"class":68,"line":694},25,[66,696,139],{"class":109},[66,698,142],{"class":113},[66,700,145],{"class":109},[66,702,171],{"class":113},[66,704,174],{"class":109},[66,706,177],{"class":113},[66,708,180],{"class":109},[66,710,142],{"class":113},[66,712,185],{"class":109},[66,714,142],{"class":113},[66,716,190],{"class":109},[66,718,193],{"class":113},[66,720,197],{"class":196},[66,722,200],{"class":113},[66,724,726],{"class":68,"line":725},26,[66,727,100],{"emptyLinePlaceholder":99},[66,729,731,733,735,737,739,742],{"class":68,"line":730},27,[66,732,211],{"class":109},[66,734,142],{"class":113},[66,736,216],{"class":109},[66,738,193],{"class":113},[66,740,741],{"class":76},"\"main：注册 async_wait\"",[66,743,224],{"class":113},[66,745,747],{"class":68,"line":746},28,[66,748,100],{"emptyLinePlaceholder":99},[66,750,752],{"class":68,"line":751},29,[66,753,754],{"class":126},"    \u002F\u002F 注册异步等待：这一行不会阻塞，回调会在定时器到期后执行。\n",[66,756,758,760,763,765,767,769,772,775,777,779,782],{"class":68,"line":757},30,[66,759,241],{"class":113},[66,761,762],{"class":109},"async_wait",[66,764,193],{"class":113},[66,766,180],{"class":109},[66,768,142],{"class":113},[66,770,771],{"class":109},"bind",[66,773,774],{"class":113},"(on_timer, ",[66,776,180],{"class":109},[66,778,142],{"class":113},[66,780,781],{"class":109},"placeholders",[66,783,784],{"class":113},"::_1));\n",[66,786,788],{"class":68,"line":787},31,[66,789,100],{"emptyLinePlaceholder":99},[66,791,793,795,797,799,801,804],{"class":68,"line":792},32,[66,794,211],{"class":109},[66,796,142],{"class":113},[66,798,216],{"class":109},[66,800,193],{"class":113},[66,802,803],{"class":76},"\"main：async_wait 已经返回，但回调还没执行\"",[66,805,224],{"class":113},[66,807,809,811,813,815,817,820],{"class":68,"line":808},33,[66,810,211],{"class":109},[66,812,142],{"class":113},[66,814,216],{"class":109},[66,816,193],{"class":113},[66,818,819],{"class":76},"\"main：准备调用 io.run()\"",[66,821,224],{"class":113},[66,823,825],{"class":68,"line":824},34,[66,826,100],{"emptyLinePlaceholder":99},[66,828,830,833,836],{"class":68,"line":829},35,[66,831,832],{"class":113},"    io.",[66,834,835],{"class":109},"run",[66,837,247],{"class":113},[66,839,841],{"class":68,"line":840},36,[66,842,100],{"emptyLinePlaceholder":99},[66,844,846,848,850,852,854,857],{"class":68,"line":845},37,[66,847,211],{"class":109},[66,849,142],{"class":113},[66,851,216],{"class":109},[66,853,193],{"class":113},[66,855,856],{"class":76},"\"main：io.run() 返回，程序结束\"",[66,858,224],{"class":113},[66,860,862],{"class":68,"line":861},38,[66,863,100],{"emptyLinePlaceholder":99},[66,865,867,869,871],{"class":68,"line":866},39,[66,868,279],{"class":72},[66,870,282],{"class":196},[66,872,285],{"class":113},[66,874,876],{"class":68,"line":875},40,[66,877,291],{"class":113},[15,879,880,298],{},[295,881,297],{},[47,883,301],{"id":884},"运行输出与时间顺序-1",[15,886,887],{},"程序立刻输出：",[57,889,892],{"className":890,"code":891,"language":307,"meta":62},[305],"main：注册 async_wait\nmain：async_wait 已经返回，但回调还没执行\nmain：准备调用 io.run()\n",[23,893,891],{"__ignoreMap":62},[15,895,896],{},"然后程序会卡在：",[57,898,900],{"className":59,"code":899,"language":61,"meta":62,"style":62},"io.run();\n",[23,901,902],{"__ignoreMap":62},[66,903,904,907,909],{"class":68,"line":69},[66,905,906],{"class":113},"io.",[66,908,835],{"class":109},[66,910,247],{"class":113},[15,912,913],{},"等待约 2 秒后输出：",[57,915,918],{"className":916,"code":917,"language":307,"meta":62},[305],"回调函数 on_timer：2 秒到了\nmain：io.run() 返回，程序结束\n",[23,919,917],{"__ignoreMap":62},[15,921,321],{},[57,923,926],{"className":924,"code":925,"language":307,"meta":62},[305],"main：注册 async_wait\nmain：async_wait 已经返回，但回调还没执行\nmain：准备调用 io.run()\n回调函数 on_timer：2 秒到了\nmain：io.run() 返回，程序结束\n",[23,927,925],{"__ignoreMap":62},[47,929,330],{"id":930},"本示例需要注意的点-1",[15,932,933,935,936,938],{},[23,934,478],{}," 不会等待 2 秒。它只是把“2 秒后执行回调”这件事注册到 ",[23,937,404],{}," 里。",[15,940,941],{},"真正等待的是：",[57,943,944],{"className":59,"code":899,"language":61,"meta":62,"style":62},[23,945,946],{"__ignoreMap":62},[66,947,948,950,952],{"class":68,"line":69},[66,949,906],{"class":113},[66,951,835],{"class":109},[66,953,247],{"class":113},[15,955,956,957,959],{},"所以不要把 ",[23,958,478],{}," 理解成“异步版本的 wait”。更准确地说：",[57,961,964],{"className":962,"code":963,"language":307,"meta":62},[305],"async_wait() = 注册任务\nio.run() = 执行事件循环\non_timer() = 任务完成后的回调\n",[23,965,963],{"__ignoreMap":62},[47,967,969,971],{"id":968},"stdbind-说明",[23,970,32],{}," 说明",[15,973,974],{},"这句代码：",[57,976,978],{"className":59,"code":977,"language":61,"meta":62,"style":62},"timer.async_wait(std::bind(on_timer, std::placeholders::_1));\n",[23,979,980],{"__ignoreMap":62},[66,981,982,984,986,988,990,992,994,996,998,1000,1002],{"class":68,"line":69},[66,983,350],{"class":113},[66,985,762],{"class":109},[66,987,193],{"class":113},[66,989,180],{"class":109},[66,991,142],{"class":113},[66,993,771],{"class":109},[66,995,774],{"class":113},[66,997,180],{"class":109},[66,999,142],{"class":113},[66,1001,781],{"class":109},[66,1003,784],{"class":113},[15,1005,1006],{},"意思是：",[57,1008,1011],{"className":1009,"code":1010,"language":307,"meta":62},[305],"当 timer 到期后，Boost.Asio 会传入一个 error_code。\n这个 error_code 会填到 std::placeholders::_1 的位置。\n最后调用 on_timer(ec)。\n",[23,1012,1010],{"__ignoreMap":62},[15,1014,1015,1018],{},[23,1016,1017],{},"on_timer"," 的函数签名必须能接收这个参数：",[57,1020,1022],{"className":59,"code":1021,"language":61,"meta":62,"style":62},"void on_timer(const boost::system::error_code& ec)\n",[23,1023,1024],{"__ignoreMap":62},[66,1025,1026,1028,1030,1032,1034,1036,1038,1040,1042,1044,1046,1048],{"class":68,"line":69},[66,1027,447],{"class":72},[66,1029,545],{"class":109},[66,1031,193],{"class":113},[66,1033,550],{"class":72},[66,1035,553],{"class":109},[66,1037,142],{"class":113},[66,1039,558],{"class":109},[66,1041,142],{"class":113},[66,1043,563],{"class":109},[66,1045,566],{"class":72},[66,1047,570],{"class":569},[66,1049,429],{"class":113},[47,1051,360],{"id":1052},"关键函数说明-1",[362,1054,1056],{"id":1055},"timerasync_waithandler",[23,1057,1058],{},"timer.async_wait(handler)",[15,1060,1061],{},"作用：注册一个异步等待操作。",[15,1063,1064],{},"参数：一个回调函数对象。",[15,1066,444,1067,448],{},[23,1068,447],{},[15,1070,1071],{},"注意：它不会阻塞等待定时器到期，只负责注册。",[362,1073,1075],{"id":1074},"iorun",[23,1076,484],{},[15,1078,1079],{},"作用：启动事件循环，处理异步任务和回调函数。",[15,1081,1082,1083,448],{},"返回值：执行过的 handler 数量，类型通常可以看成 ",[23,1084,1085],{},"std::size_t",[15,1087,1088,1089,1091],{},"本例中，",[23,1090,484],{}," 执行了 1 个回调，所以返回值是 1。只是我们没有打印返回值。",[35,1093],{},[38,1095,1097,1098,1100],{"id":1096},"示例-3普通-main-里写两个异步定时器","示例 3：普通 ",[23,1099,44],{}," 里写两个异步定时器",[47,1102,49],{"id":1103},"程序目标-2",[15,1105,1106],{},"一个 timer 很难看出异步调度的感觉，所以这次写两个 timer：",[468,1108,1109,1115,1121,1127],{},[471,1110,1111,1114],{},[23,1112,1113],{},"timer1"," 1 秒后到期；",[471,1116,1117,1120],{},[23,1118,1119],{},"timer2"," 3 秒后到期；",[471,1122,1123,1124,1126],{},"两个 timer 都在同一个 ",[23,1125,404],{}," 里；",[471,1128,1129,1131],{},[23,1130,484],{}," 会等两个任务都完成后才返回。",[47,1133,55],{"id":1134},"完整代码-2",[57,1136,1138],{"className":59,"code":1137,"language":61,"meta":62,"style":62},"#include \u003Cboost\u002Fasio.hpp>\n#include \u003Cboost\u002Fsystem\u002Ferror_code.hpp>\n#include \u003Cchrono>\n#include \u003Cfunctional>\n#include \u003Cprint>\n#include \u003Cstring>\n\nvoid on_timer(const boost::system::error_code& ec, const std::string& name)\n{\n    if (ec)\n    {\n        std::println(\"{} 被取消：{}\", name, ec.message());\n        return;\n    }\n\n    std::println(\"{} 到期，执行回调\", name);\n}\n\nint main()\n{\n    \u002F\u002F 程序从 main 函数开始执行，下面的语句会按顺序运行。\n    \u002F\u002F io_context 是 Asio 的事件循环对象，异步任务需要靠它调度。\n    boost::asio::io_context io;\n\n    \u002F\u002F 创建定时器，并设置到期时间。\n    boost::asio::steady_timer timer1(io, std::chrono::seconds(1));\n    boost::asio::steady_timer timer2(io, std::chrono::seconds(3));\n\n    std::println(\"main：注册 timer1，1 秒后到期\");\n    \u002F\u002F 注册异步等待：这一行不会阻塞，回调会在定时器到期后执行。\n    timer1.async_wait(std::bind(on_timer,\n                                std::placeholders::_1,\n                                std::string(\"timer1\")));\n\n    std::println(\"main：注册 timer2，3 秒后到期\");\n    timer2.async_wait(std::bind(on_timer,\n                                std::placeholders::_1,\n                                std::string(\"timer2\")));\n\n    std::println(\"main：调用 io.run()\");\n\n    std::size_t count = io.run();\n\n    std::println(\"main：io.run() 返回，一共执行了 {} 个回调\", count);\n\n    return 0;\n}\n",[23,1139,1140,1146,1152,1158,1164,1170,1177,1181,1225,1229,1235,1239,1259,1265,1269,1273,1289,1293,1297,1305,1309,1313,1317,1327,1331,1335,1366,1397,1401,1416,1420,1438,1450,1466,1470,1485,1502,1512,1527,1531,1546,1551,1574,1579,1596,1601,1610],{"__ignoreMap":62},[66,1141,1142,1144],{"class":68,"line":69},[66,1143,73],{"class":72},[66,1145,77],{"class":76},[66,1147,1148,1150],{"class":68,"line":80},[66,1149,73],{"class":72},[66,1151,515],{"class":76},[66,1153,1154,1156],{"class":68,"line":88},[66,1155,73],{"class":72},[66,1157,85],{"class":76},[66,1159,1160,1162],{"class":68,"line":96},[66,1161,73],{"class":72},[66,1163,528],{"class":76},[66,1165,1166,1168],{"class":68,"line":103},[66,1167,73],{"class":72},[66,1169,93],{"class":76},[66,1171,1172,1174],{"class":68,"line":117},[66,1173,73],{"class":72},[66,1175,1176],{"class":76}," \u003Cstring>\n",[66,1178,1179],{"class":68,"line":123},[66,1180,100],{"emptyLinePlaceholder":99},[66,1182,1183,1185,1187,1189,1191,1193,1195,1197,1199,1201,1203,1205,1208,1210,1213,1215,1218,1220,1223],{"class":68,"line":130},[66,1184,447],{"class":72},[66,1186,545],{"class":109},[66,1188,193],{"class":113},[66,1190,550],{"class":72},[66,1192,553],{"class":109},[66,1194,142],{"class":113},[66,1196,558],{"class":109},[66,1198,142],{"class":113},[66,1200,563],{"class":109},[66,1202,566],{"class":72},[66,1204,570],{"class":569},[66,1206,1207],{"class":113},", ",[66,1209,550],{"class":72},[66,1211,1212],{"class":109}," std",[66,1214,142],{"class":113},[66,1216,1217],{"class":109},"string",[66,1219,566],{"class":72},[66,1221,1222],{"class":569}," name",[66,1224,429],{"class":113},[66,1226,1227],{"class":68,"line":136},[66,1228,120],{"class":113},[66,1230,1231,1233],{"class":68,"line":151},[66,1232,581],{"class":72},[66,1234,584],{"class":113},[66,1236,1237],{"class":68,"line":156},[66,1238,589],{"class":113},[66,1240,1241,1243,1245,1247,1249,1252,1255,1257],{"class":68,"line":162},[66,1242,594],{"class":109},[66,1244,142],{"class":113},[66,1246,216],{"class":109},[66,1248,193],{"class":113},[66,1250,1251],{"class":76},"\"{} 被取消：{}\"",[66,1253,1254],{"class":113},", name, ec.",[66,1256,609],{"class":109},[66,1258,612],{"class":113},[66,1260,1261,1263],{"class":68,"line":203},[66,1262,617],{"class":72},[66,1264,285],{"class":113},[66,1266,1267],{"class":68,"line":208},[66,1268,624],{"class":113},[66,1270,1271],{"class":68,"line":227},[66,1272,100],{"emptyLinePlaceholder":99},[66,1274,1275,1277,1279,1281,1283,1286],{"class":68,"line":232},[66,1276,211],{"class":109},[66,1278,142],{"class":113},[66,1280,216],{"class":109},[66,1282,193],{"class":113},[66,1284,1285],{"class":76},"\"{} 到期，执行回调\"",[66,1287,1288],{"class":113},", name);\n",[66,1290,1291],{"class":68,"line":238},[66,1292,291],{"class":113},[66,1294,1295],{"class":68,"line":250},[66,1296,100],{"emptyLinePlaceholder":99},[66,1298,1299,1301,1303],{"class":68,"line":255},[66,1300,106],{"class":72},[66,1302,110],{"class":109},[66,1304,114],{"class":113},[66,1306,1307],{"class":68,"line":271},[66,1308,120],{"class":113},[66,1310,1311],{"class":68,"line":276},[66,1312,127],{"class":126},[66,1314,1315],{"class":68,"line":288},[66,1316,133],{"class":126},[66,1318,1319,1321,1323,1325],{"class":68,"line":684},[66,1320,139],{"class":109},[66,1322,142],{"class":113},[66,1324,145],{"class":109},[66,1326,148],{"class":113},[66,1328,1329],{"class":68,"line":689},[66,1330,100],{"emptyLinePlaceholder":99},[66,1332,1333],{"class":68,"line":694},[66,1334,159],{"class":126},[66,1336,1337,1339,1341,1343,1345,1347,1349,1351,1353,1355,1357,1359,1361,1364],{"class":68,"line":725},[66,1338,139],{"class":109},[66,1340,142],{"class":113},[66,1342,145],{"class":109},[66,1344,171],{"class":113},[66,1346,1113],{"class":109},[66,1348,177],{"class":113},[66,1350,180],{"class":109},[66,1352,142],{"class":113},[66,1354,185],{"class":109},[66,1356,142],{"class":113},[66,1358,190],{"class":109},[66,1360,193],{"class":113},[66,1362,1363],{"class":196},"1",[66,1365,200],{"class":113},[66,1367,1368,1370,1372,1374,1376,1378,1380,1382,1384,1386,1388,1390,1392,1395],{"class":68,"line":730},[66,1369,139],{"class":109},[66,1371,142],{"class":113},[66,1373,145],{"class":109},[66,1375,171],{"class":113},[66,1377,1119],{"class":109},[66,1379,177],{"class":113},[66,1381,180],{"class":109},[66,1383,142],{"class":113},[66,1385,185],{"class":109},[66,1387,142],{"class":113},[66,1389,190],{"class":109},[66,1391,193],{"class":113},[66,1393,1394],{"class":196},"3",[66,1396,200],{"class":113},[66,1398,1399],{"class":68,"line":746},[66,1400,100],{"emptyLinePlaceholder":99},[66,1402,1403,1405,1407,1409,1411,1414],{"class":68,"line":751},[66,1404,211],{"class":109},[66,1406,142],{"class":113},[66,1408,216],{"class":109},[66,1410,193],{"class":113},[66,1412,1413],{"class":76},"\"main：注册 timer1，1 秒后到期\"",[66,1415,224],{"class":113},[66,1417,1418],{"class":68,"line":757},[66,1419,754],{"class":126},[66,1421,1422,1425,1427,1429,1431,1433,1435],{"class":68,"line":787},[66,1423,1424],{"class":113},"    timer1.",[66,1426,762],{"class":109},[66,1428,193],{"class":113},[66,1430,180],{"class":109},[66,1432,142],{"class":113},[66,1434,771],{"class":109},[66,1436,1437],{"class":113},"(on_timer,\n",[66,1439,1440,1443,1445,1447],{"class":68,"line":792},[66,1441,1442],{"class":109},"                                std",[66,1444,142],{"class":113},[66,1446,781],{"class":109},[66,1448,1449],{"class":113},"::_1,\n",[66,1451,1452,1454,1456,1458,1460,1463],{"class":68,"line":808},[66,1453,1442],{"class":109},[66,1455,142],{"class":113},[66,1457,1217],{"class":109},[66,1459,193],{"class":113},[66,1461,1462],{"class":76},"\"timer1\"",[66,1464,1465],{"class":113},")));\n",[66,1467,1468],{"class":68,"line":824},[66,1469,100],{"emptyLinePlaceholder":99},[66,1471,1472,1474,1476,1478,1480,1483],{"class":68,"line":829},[66,1473,211],{"class":109},[66,1475,142],{"class":113},[66,1477,216],{"class":109},[66,1479,193],{"class":113},[66,1481,1482],{"class":76},"\"main：注册 timer2，3 秒后到期\"",[66,1484,224],{"class":113},[66,1486,1487,1490,1492,1494,1496,1498,1500],{"class":68,"line":840},[66,1488,1489],{"class":113},"    timer2.",[66,1491,762],{"class":109},[66,1493,193],{"class":113},[66,1495,180],{"class":109},[66,1497,142],{"class":113},[66,1499,771],{"class":109},[66,1501,1437],{"class":113},[66,1503,1504,1506,1508,1510],{"class":68,"line":845},[66,1505,1442],{"class":109},[66,1507,142],{"class":113},[66,1509,781],{"class":109},[66,1511,1449],{"class":113},[66,1513,1514,1516,1518,1520,1522,1525],{"class":68,"line":861},[66,1515,1442],{"class":109},[66,1517,142],{"class":113},[66,1519,1217],{"class":109},[66,1521,193],{"class":113},[66,1523,1524],{"class":76},"\"timer2\"",[66,1526,1465],{"class":113},[66,1528,1529],{"class":68,"line":866},[66,1530,100],{"emptyLinePlaceholder":99},[66,1532,1533,1535,1537,1539,1541,1544],{"class":68,"line":875},[66,1534,211],{"class":109},[66,1536,142],{"class":113},[66,1538,216],{"class":109},[66,1540,193],{"class":113},[66,1542,1543],{"class":76},"\"main：调用 io.run()\"",[66,1545,224],{"class":113},[66,1547,1549],{"class":68,"line":1548},41,[66,1550,100],{"emptyLinePlaceholder":99},[66,1552,1554,1556,1558,1561,1564,1567,1570,1572],{"class":68,"line":1553},42,[66,1555,211],{"class":109},[66,1557,142],{"class":113},[66,1559,1560],{"class":72},"size_t",[66,1562,1563],{"class":113}," count ",[66,1565,1566],{"class":72},"=",[66,1568,1569],{"class":113}," io.",[66,1571,835],{"class":109},[66,1573,247],{"class":113},[66,1575,1577],{"class":68,"line":1576},43,[66,1578,100],{"emptyLinePlaceholder":99},[66,1580,1582,1584,1586,1588,1590,1593],{"class":68,"line":1581},44,[66,1583,211],{"class":109},[66,1585,142],{"class":113},[66,1587,216],{"class":109},[66,1589,193],{"class":113},[66,1591,1592],{"class":76},"\"main：io.run() 返回，一共执行了 {} 个回调\"",[66,1594,1595],{"class":113},", count);\n",[66,1597,1599],{"class":68,"line":1598},45,[66,1600,100],{"emptyLinePlaceholder":99},[66,1602,1604,1606,1608],{"class":68,"line":1603},46,[66,1605,279],{"class":72},[66,1607,282],{"class":196},[66,1609,285],{"class":113},[66,1611,1613],{"class":68,"line":1612},47,[66,1614,291],{"class":113},[15,1616,1617,298],{},[295,1618,297],{},[47,1620,301],{"id":1621},"运行输出与时间顺序-2",[15,1623,887],{},[57,1625,1628],{"className":1626,"code":1627,"language":307,"meta":62},[305],"main：注册 timer1，1 秒后到期\nmain：注册 timer2，3 秒后到期\nmain：调用 io.run()\n",[23,1629,1627],{"__ignoreMap":62},[15,1631,1632],{},"约 1 秒后输出：",[57,1634,1637],{"className":1635,"code":1636,"language":307,"meta":62},[305],"timer1 到期，执行回调\n",[23,1638,1636],{"__ignoreMap":62},[15,1640,1641],{},"再过约 2 秒，也就是程序启动后约 3 秒，输出：",[57,1643,1646],{"className":1644,"code":1645,"language":307,"meta":62},[305],"timer2 到期，执行回调\nmain：io.run() 返回，一共执行了 2 个回调\n",[23,1647,1645],{"__ignoreMap":62},[15,1649,321],{},[57,1651,1654],{"className":1652,"code":1653,"language":307,"meta":62},[305],"main：注册 timer1，1 秒后到期\nmain：注册 timer2，3 秒后到期\nmain：调用 io.run()\ntimer1 到期，执行回调\ntimer2 到期，执行回调\nmain：io.run() 返回，一共执行了 2 个回调\n",[23,1655,1653],{"__ignoreMap":62},[47,1657,330],{"id":1658},"本示例需要注意的点-2",[15,1660,1661],{},"两个 timer 不是两个线程。",[15,1663,1664,1665,1667,1668,1670,1671,1673],{},"本例只有一个线程，也就是主线程。",[23,1666,1113],{}," 和 ",[23,1669,1119],{}," 的回调都在调用 ",[23,1672,484],{}," 的这个主线程里执行。",[15,1675,1676],{},"真正的执行顺序是：",[57,1678,1681],{"className":1679,"code":1680,"language":307,"meta":62},[305],"主线程进入 io.run()\n等待事件\ntimer1 先到期 -> 调用 timer1 回调\n继续等待事件\ntimer2 后到期 -> 调用 timer2 回调\n没有任务了 -> io.run() 返回\n",[23,1682,1680],{"__ignoreMap":62},[15,1684,1685,1686,1689],{},"他和",[23,1687,1688],{},"std::this_thread::sleep_for()","不一样，线程里的睡眠是一个阻塞式延迟，而这里的定时器只是一个事件，类似于中断。",[47,1691,1693,1695],{"id":1692},"stdbind-里的固定参数",[23,1694,32],{}," 里的固定参数",[15,1697,1698],{},"这句：",[57,1700,1702],{"className":59,"code":1701,"language":61,"meta":62,"style":62},"std::bind(on_timer, std::placeholders::_1, std::string(\"timer1\"))\n",[23,1703,1704],{"__ignoreMap":62},[66,1705,1706,1708,1710,1712,1714,1716,1718,1720,1723,1725,1727,1729,1731,1733],{"class":68,"line":69},[66,1707,180],{"class":109},[66,1709,142],{"class":113},[66,1711,771],{"class":109},[66,1713,774],{"class":113},[66,1715,180],{"class":109},[66,1717,142],{"class":113},[66,1719,781],{"class":109},[66,1721,1722],{"class":113},"::_1, ",[66,1724,180],{"class":109},[66,1726,142],{"class":113},[66,1728,1217],{"class":109},[66,1730,193],{"class":113},[66,1732,1462],{"class":76},[66,1734,1735],{"class":113},"))\n",[15,1737,1738],{},"等价于提前准备了一个函数对象：",[57,1740,1743],{"className":1741,"code":1742,"language":307,"meta":62},[305],"未来 Asio 传入 ec 时，调用 on_timer(ec, \"timer1\")。\n",[23,1744,1742],{"__ignoreMap":62},[15,1746,1747,1750],{},[23,1748,1749],{},"_1"," 是未来由 Asio 传入的错误码。",[15,1752,1753,1755],{},[23,1754,1462],{}," 是现在就固定好的参数。",[35,1757],{},[38,1759,1761,1762,1764],{"id":1760},"示例-4普通-main-里写重复定时器","示例 4：普通 ",[23,1763,44],{}," 里写重复定时器",[47,1766,49],{"id":1767},"程序目标-3",[15,1769,1770],{},"实现一个每 1 秒打印一次的定时器，打印 5 次后结束。",[15,1772,1773],{},"这个例子很像机器人里的周期任务，例如：",[57,1775,1778],{"className":1776,"code":1777,"language":307,"meta":62},[305],"每 20ms 发送一次速度命令\n每 100ms 检查一次下位机心跳\n每 1s 打印一次通信状态\n",[23,1779,1777],{"__ignoreMap":62},[47,1781,55],{"id":1782},"完整代码-3",[57,1784,1786],{"className":59,"code":1785,"language":61,"meta":62,"style":62},"#include \u003Cboost\u002Fasio.hpp>\n#include \u003Cboost\u002Fsystem\u002Ferror_code.hpp>\n#include \u003Cchrono>\n#include \u003Cfunctional>\n#include \u003Cprint>\n\nvoid repeat_timer(const boost::system::error_code& ec,\n                  boost::asio::steady_timer* timer,\n                  int* count)\n{\n    if (ec)\n    {\n        std::println(\"repeat_timer 被取消：{}\", ec.message());\n        return;\n    }\n\n    ++(*count);\n    std::println(\"第 {} 次定时器回调\", *count);\n\n    if (*count \u003C 5)\n    {\n        \u002F\u002F 重新设置下一次到期时间，并再次注册异步等待，使定时器继续周期执行。\n        timer->expires_after(std::chrono::seconds(1));\n        timer->async_wait(std::bind(repeat_timer,\n                                    std::placeholders::_1,\n                                    timer,\n                                    count));\n    }\n    else\n    {\n        std::println(\"已经执行 5 次，不再重新注册定时器\");\n    }\n}\n\nint main()\n{\n    \u002F\u002F 程序从 main 函数开始执行，下面的语句会按顺序运行。\n    \u002F\u002F io_context 是 Asio 的事件循环对象，异步任务需要靠它调度。\n    boost::asio::io_context io;\n    \u002F\u002F 创建定时器，并设置到期时间。\n    boost::asio::steady_timer timer(io, std::chrono::seconds(1));\n    int count = 0;\n\n    std::println(\"main：注册第 1 次定时器\");\n\n    \u002F\u002F 注册异步等待：这一行不会阻塞，回调会在定时器到期后执行。\n    timer.async_wait(std::bind(repeat_timer,\n                               std::placeholders::_1,\n                               &timer,\n                               &count));\n\n    io.run();\n\n    std::println(\"main：io.run() 返回，程序结束\");\n\n    return 0;\n}\n",[23,1787,1788,1794,1800,1806,1812,1818,1822,1850,1872,1882,1886,1892,1896,1915,1921,1925,1929,1941,1960,1964,1984,1988,1993,2019,2036,2047,2052,2057,2061,2066,2070,2085,2089,2093,2097,2105,2109,2113,2117,2127,2131,2161,2174,2178,2193,2197,2201,2217,2229,2238,2246,2251,2260,2265,2280,2285,2294],{"__ignoreMap":62},[66,1789,1790,1792],{"class":68,"line":69},[66,1791,73],{"class":72},[66,1793,77],{"class":76},[66,1795,1796,1798],{"class":68,"line":80},[66,1797,73],{"class":72},[66,1799,515],{"class":76},[66,1801,1802,1804],{"class":68,"line":88},[66,1803,73],{"class":72},[66,1805,85],{"class":76},[66,1807,1808,1810],{"class":68,"line":96},[66,1809,73],{"class":72},[66,1811,528],{"class":76},[66,1813,1814,1816],{"class":68,"line":103},[66,1815,73],{"class":72},[66,1817,93],{"class":76},[66,1819,1820],{"class":68,"line":117},[66,1821,100],{"emptyLinePlaceholder":99},[66,1823,1824,1826,1829,1831,1833,1835,1837,1839,1841,1843,1845,1847],{"class":68,"line":123},[66,1825,447],{"class":72},[66,1827,1828],{"class":109}," repeat_timer",[66,1830,193],{"class":113},[66,1832,550],{"class":72},[66,1834,553],{"class":109},[66,1836,142],{"class":113},[66,1838,558],{"class":109},[66,1840,142],{"class":113},[66,1842,563],{"class":109},[66,1844,566],{"class":72},[66,1846,570],{"class":569},[66,1848,1849],{"class":113},",\n",[66,1851,1852,1855,1857,1859,1861,1864,1867,1870],{"class":68,"line":130},[66,1853,1854],{"class":109},"                  boost",[66,1856,142],{"class":113},[66,1858,145],{"class":109},[66,1860,142],{"class":113},[66,1862,1863],{"class":109},"steady_timer",[66,1865,1866],{"class":72},"*",[66,1868,1869],{"class":569}," timer",[66,1871,1849],{"class":113},[66,1873,1874,1877,1880],{"class":68,"line":136},[66,1875,1876],{"class":72},"                  int*",[66,1878,1879],{"class":569}," count",[66,1881,429],{"class":113},[66,1883,1884],{"class":68,"line":151},[66,1885,120],{"class":113},[66,1887,1888,1890],{"class":68,"line":156},[66,1889,581],{"class":72},[66,1891,584],{"class":113},[66,1893,1894],{"class":68,"line":162},[66,1895,589],{"class":113},[66,1897,1898,1900,1902,1904,1906,1909,1911,1913],{"class":68,"line":203},[66,1899,594],{"class":109},[66,1901,142],{"class":113},[66,1903,216],{"class":109},[66,1905,193],{"class":113},[66,1907,1908],{"class":76},"\"repeat_timer 被取消：{}\"",[66,1910,606],{"class":113},[66,1912,609],{"class":109},[66,1914,612],{"class":113},[66,1916,1917,1919],{"class":68,"line":208},[66,1918,617],{"class":72},[66,1920,285],{"class":113},[66,1922,1923],{"class":68,"line":227},[66,1924,624],{"class":113},[66,1926,1927],{"class":68,"line":232},[66,1928,100],{"emptyLinePlaceholder":99},[66,1930,1931,1934,1936,1938],{"class":68,"line":238},[66,1932,1933],{"class":72},"    ++",[66,1935,193],{"class":113},[66,1937,1866],{"class":72},[66,1939,1940],{"class":113},"count);\n",[66,1942,1943,1945,1947,1949,1951,1954,1956,1958],{"class":68,"line":250},[66,1944,211],{"class":109},[66,1946,142],{"class":113},[66,1948,216],{"class":109},[66,1950,193],{"class":113},[66,1952,1953],{"class":76},"\"第 {} 次定时器回调\"",[66,1955,1207],{"class":113},[66,1957,1866],{"class":72},[66,1959,1940],{"class":113},[66,1961,1962],{"class":68,"line":255},[66,1963,100],{"emptyLinePlaceholder":99},[66,1965,1966,1968,1971,1973,1976,1979,1982],{"class":68,"line":271},[66,1967,581],{"class":72},[66,1969,1970],{"class":113}," (",[66,1972,1866],{"class":72},[66,1974,1975],{"class":113},"count ",[66,1977,1978],{"class":72},"\u003C",[66,1980,1981],{"class":196}," 5",[66,1983,429],{"class":113},[66,1985,1986],{"class":68,"line":276},[66,1987,589],{"class":113},[66,1989,1990],{"class":68,"line":288},[66,1991,1992],{"class":126},"        \u002F\u002F 重新设置下一次到期时间，并再次注册异步等待，使定时器继续周期执行。\n",[66,1994,1995,1998,2001,2003,2005,2007,2009,2011,2013,2015,2017],{"class":68,"line":684},[66,1996,1997],{"class":113},"        timer->",[66,1999,2000],{"class":109},"expires_after",[66,2002,193],{"class":113},[66,2004,180],{"class":109},[66,2006,142],{"class":113},[66,2008,185],{"class":109},[66,2010,142],{"class":113},[66,2012,190],{"class":109},[66,2014,193],{"class":113},[66,2016,1363],{"class":196},[66,2018,200],{"class":113},[66,2020,2021,2023,2025,2027,2029,2031,2033],{"class":68,"line":689},[66,2022,1997],{"class":113},[66,2024,762],{"class":109},[66,2026,193],{"class":113},[66,2028,180],{"class":109},[66,2030,142],{"class":113},[66,2032,771],{"class":109},[66,2034,2035],{"class":113},"(repeat_timer,\n",[66,2037,2038,2041,2043,2045],{"class":68,"line":694},[66,2039,2040],{"class":109},"                                    std",[66,2042,142],{"class":113},[66,2044,781],{"class":109},[66,2046,1449],{"class":113},[66,2048,2049],{"class":68,"line":725},[66,2050,2051],{"class":113},"                                    timer,\n",[66,2053,2054],{"class":68,"line":730},[66,2055,2056],{"class":113},"                                    count));\n",[66,2058,2059],{"class":68,"line":746},[66,2060,624],{"class":113},[66,2062,2063],{"class":68,"line":751},[66,2064,2065],{"class":72},"    else\n",[66,2067,2068],{"class":68,"line":757},[66,2069,589],{"class":113},[66,2071,2072,2074,2076,2078,2080,2083],{"class":68,"line":787},[66,2073,594],{"class":109},[66,2075,142],{"class":113},[66,2077,216],{"class":109},[66,2079,193],{"class":113},[66,2081,2082],{"class":76},"\"已经执行 5 次，不再重新注册定时器\"",[66,2084,224],{"class":113},[66,2086,2087],{"class":68,"line":792},[66,2088,624],{"class":113},[66,2090,2091],{"class":68,"line":808},[66,2092,291],{"class":113},[66,2094,2095],{"class":68,"line":824},[66,2096,100],{"emptyLinePlaceholder":99},[66,2098,2099,2101,2103],{"class":68,"line":829},[66,2100,106],{"class":72},[66,2102,110],{"class":109},[66,2104,114],{"class":113},[66,2106,2107],{"class":68,"line":840},[66,2108,120],{"class":113},[66,2110,2111],{"class":68,"line":845},[66,2112,127],{"class":126},[66,2114,2115],{"class":68,"line":861},[66,2116,133],{"class":126},[66,2118,2119,2121,2123,2125],{"class":68,"line":866},[66,2120,139],{"class":109},[66,2122,142],{"class":113},[66,2124,145],{"class":109},[66,2126,148],{"class":113},[66,2128,2129],{"class":68,"line":875},[66,2130,159],{"class":126},[66,2132,2133,2135,2137,2139,2141,2143,2145,2147,2149,2151,2153,2155,2157,2159],{"class":68,"line":1548},[66,2134,139],{"class":109},[66,2136,142],{"class":113},[66,2138,145],{"class":109},[66,2140,171],{"class":113},[66,2142,174],{"class":109},[66,2144,177],{"class":113},[66,2146,180],{"class":109},[66,2148,142],{"class":113},[66,2150,185],{"class":109},[66,2152,142],{"class":113},[66,2154,190],{"class":109},[66,2156,193],{"class":113},[66,2158,1363],{"class":196},[66,2160,200],{"class":113},[66,2162,2163,2166,2168,2170,2172],{"class":68,"line":1553},[66,2164,2165],{"class":72},"    int",[66,2167,1563],{"class":113},[66,2169,1566],{"class":72},[66,2171,282],{"class":196},[66,2173,285],{"class":113},[66,2175,2176],{"class":68,"line":1576},[66,2177,100],{"emptyLinePlaceholder":99},[66,2179,2180,2182,2184,2186,2188,2191],{"class":68,"line":1581},[66,2181,211],{"class":109},[66,2183,142],{"class":113},[66,2185,216],{"class":109},[66,2187,193],{"class":113},[66,2189,2190],{"class":76},"\"main：注册第 1 次定时器\"",[66,2192,224],{"class":113},[66,2194,2195],{"class":68,"line":1598},[66,2196,100],{"emptyLinePlaceholder":99},[66,2198,2199],{"class":68,"line":1603},[66,2200,754],{"class":126},[66,2202,2203,2205,2207,2209,2211,2213,2215],{"class":68,"line":1612},[66,2204,241],{"class":113},[66,2206,762],{"class":109},[66,2208,193],{"class":113},[66,2210,180],{"class":109},[66,2212,142],{"class":113},[66,2214,771],{"class":109},[66,2216,2035],{"class":113},[66,2218,2220,2223,2225,2227],{"class":68,"line":2219},48,[66,2221,2222],{"class":109},"                               std",[66,2224,142],{"class":113},[66,2226,781],{"class":109},[66,2228,1449],{"class":113},[66,2230,2232,2235],{"class":68,"line":2231},49,[66,2233,2234],{"class":72},"                               &",[66,2236,2237],{"class":113},"timer,\n",[66,2239,2241,2243],{"class":68,"line":2240},50,[66,2242,2234],{"class":72},[66,2244,2245],{"class":113},"count));\n",[66,2247,2249],{"class":68,"line":2248},51,[66,2250,100],{"emptyLinePlaceholder":99},[66,2252,2254,2256,2258],{"class":68,"line":2253},52,[66,2255,832],{"class":113},[66,2257,835],{"class":109},[66,2259,247],{"class":113},[66,2261,2263],{"class":68,"line":2262},53,[66,2264,100],{"emptyLinePlaceholder":99},[66,2266,2268,2270,2272,2274,2276,2278],{"class":68,"line":2267},54,[66,2269,211],{"class":109},[66,2271,142],{"class":113},[66,2273,216],{"class":109},[66,2275,193],{"class":113},[66,2277,856],{"class":76},[66,2279,224],{"class":113},[66,2281,2283],{"class":68,"line":2282},55,[66,2284,100],{"emptyLinePlaceholder":99},[66,2286,2288,2290,2292],{"class":68,"line":2287},56,[66,2289,279],{"class":72},[66,2291,282],{"class":196},[66,2293,285],{"class":113},[66,2295,2297],{"class":68,"line":2296},57,[66,2298,291],{"class":113},[15,2300,2301,298],{},[295,2302,297],{},[47,2304,301],{"id":2305},"运行输出与时间顺序-3",[15,2307,887],{},[57,2309,2312],{"className":2310,"code":2311,"language":307,"meta":62},[305],"main：注册第 1 次定时器\n",[23,2313,2311],{"__ignoreMap":62},[15,2315,2316],{},"约 1 秒后：",[57,2318,2321],{"className":2319,"code":2320,"language":307,"meta":62},[305],"第 1 次定时器回调\n",[23,2322,2320],{"__ignoreMap":62},[15,2324,2325],{},"之后每隔约 1 秒输出一次：",[57,2327,2330],{"className":2328,"code":2329,"language":307,"meta":62},[305],"第 2 次定时器回调\n第 3 次定时器回调\n第 4 次定时器回调\n第 5 次定时器回调\n已经执行 5 次，不再重新注册定时器\nmain：io.run() 返回，程序结束\n",[23,2331,2329],{"__ignoreMap":62},[15,2333,321],{},[57,2335,2338],{"className":2336,"code":2337,"language":307,"meta":62},[305],"main：注册第 1 次定时器\n第 1 次定时器回调\n第 2 次定时器回调\n第 3 次定时器回调\n第 4 次定时器回调\n第 5 次定时器回调\n已经执行 5 次，不再重新注册定时器\nmain：io.run() 返回，程序结束\n",[23,2339,2337],{"__ignoreMap":62},[47,2341,330],{"id":2342},"本示例需要注意的点-3",[15,2344,2345,2346,2349,2350,448],{},"重复定时器不是 ",[23,2347,2348],{},"while"," 循环里 ",[23,2351,2352],{},"sleep",[15,2354,2355],{},"异步写法是：",[57,2357,2360],{"className":2358,"code":2359,"language":307,"meta":62},[305],"第一次 async_wait\n第 1 次回调里重新设置 expires_after\n第 1 次回调里再次 async_wait\n第 2 次回调里再次注册\n……\n",[23,2361,2359],{"__ignoreMap":62},[15,2363,2364],{},"也就是“每次回调结束前，决定要不要注册下一次”。",[57,2366,2368],{"className":59,"code":2367,"language":61,"meta":62,"style":62},"        \u002F\u002F 重新设置下一次到期时间，并再次注册异步等待，使定时器继续周期执行。\n        timer->expires_after(std::chrono::seconds(1));\n        timer->async_wait(std::bind(repeat_timer,\n                                    std::placeholders::_1,\n                                    timer,\n                                    count));\n",[23,2369,2370,2374,2398,2414,2424,2428],{"__ignoreMap":62},[66,2371,2372],{"class":68,"line":69},[66,2373,1992],{"class":126},[66,2375,2376,2378,2380,2382,2384,2386,2388,2390,2392,2394,2396],{"class":68,"line":80},[66,2377,1997],{"class":113},[66,2379,2000],{"class":109},[66,2381,193],{"class":113},[66,2383,180],{"class":109},[66,2385,142],{"class":113},[66,2387,185],{"class":109},[66,2389,142],{"class":113},[66,2391,190],{"class":109},[66,2393,193],{"class":113},[66,2395,1363],{"class":196},[66,2397,200],{"class":113},[66,2399,2400,2402,2404,2406,2408,2410,2412],{"class":68,"line":88},[66,2401,1997],{"class":113},[66,2403,762],{"class":109},[66,2405,193],{"class":113},[66,2407,180],{"class":109},[66,2409,142],{"class":113},[66,2411,771],{"class":109},[66,2413,2035],{"class":113},[66,2415,2416,2418,2420,2422],{"class":68,"line":96},[66,2417,2040],{"class":109},[66,2419,142],{"class":113},[66,2421,781],{"class":109},[66,2423,1449],{"class":113},[66,2425,2426],{"class":68,"line":103},[66,2427,2051],{"class":113},[66,2429,2430],{"class":68,"line":117},[66,2431,2056],{"class":113},[15,2433,2434],{},"上面这两行很重要：",[15,2436,2437,2440],{},[23,2438,2439],{},"timer->expires_after(std::chrono::seconds(1));","是把定时器的到期时间重新设置为“从现在开始 1 秒后”。它本身不会注册回调，也不会阻塞线程，只是修改定时器的到期时间。",[15,2442,2443,2446],{},[23,2444,2445],{},"timer->async_wait(std::bind(repeat_timer,std::placeholders::_1,timer,count));","决定了到期以后执行谁。",[15,2448,2449],{},"因此这两行可以理解成：“给下一轮定时器续命”。",[15,2451,2452,2455],{},[23,2453,2454],{},"boost::asio::steady_timer timer(io, std::chrono::seconds(1));","只是把第一次到期时间设成“现在之后 1 秒”。第一次到期以后，如果你不再调用上面这两行，那么定时器的到期时间还是原来的那个时间点，已经过去了。",[15,2457,2458,2459,2462,2463,2465],{},"如果你不用",[23,2460,2461],{},"expires_after()","设定新的时间，那么直接调用",[23,2464,478],{},"会导致回调基本会立刻执行。",[47,2467,2468],{"id":2468},"指针生命周期说明",[15,2470,2471],{},"本例里传了：",[57,2473,2475],{"className":59,"code":2474,"language":61,"meta":62,"style":62},"&timer\n&count\n",[23,2476,2477,2484],{"__ignoreMap":62},[66,2478,2479,2481],{"class":68,"line":69},[66,2480,566],{"class":72},[66,2482,2483],{"class":113},"timer\n",[66,2485,2486,2488],{"class":68,"line":80},[66,2487,566],{"class":72},[66,2489,2490],{"class":113},"count\n",[15,2492,2493,2494,2497],{},"这是为了让 ",[23,2495,2496],{},"repeat_timer()"," 能修改同一个 timer 和 count。",[15,2499,2500],{},"这个写法在本例中是安全的，因为：",[57,2502,2505],{"className":2503,"code":2504,"language":307,"meta":62},[305],"timer 和 count 都是 main() 里的局部变量\nmain() 会卡在 io.run()\nio.run() 返回前，timer 和 count 都不会析构\n",[23,2506,2504],{"__ignoreMap":62},[15,2508,2509],{},"但是工程里更推荐把它封装成类，见下一个示例。",[35,2511],{},[38,2513,2515],{"id":2514},"示例-5类里写单个异步定时器","示例 5：类里写单个异步定时器",[47,2517,49],{"id":2518},"程序目标-4",[15,2520,2521],{},"把示例 2 改成类封装版本。",[15,2523,2524],{},"类封装是机器人项目里更常见的写法，例如：",[57,2526,2529],{"className":2527,"code":2528,"language":307,"meta":62},[305],"SerialDriver 类\nTcpClient 类\nUdpReceiver 类\nRobotController 类\n",[23,2530,2528],{"__ignoreMap":62},[47,2532,55],{"id":2533},"完整代码-4",[57,2535,2537],{"className":59,"code":2536,"language":61,"meta":62,"style":62},"#include \u003Cboost\u002Fasio.hpp>\n#include \u003Cboost\u002Fsystem\u002Ferror_code.hpp>\n#include \u003Cchrono>\n#include \u003Cfunctional>\n#include \u003Cprint>\n\nclass Printer\n{\npublic:\n    explicit Printer(boost::asio::io_context& io)\n        : timer_(io, std::chrono::seconds(2))\n    {\n        std::println(\"Printer 构造：注册 2 秒定时器\");\n\n        \u002F\u002F 注册异步等待：这一行不会阻塞，回调会在定时器到期后执行。\n        timer_.async_wait(std::bind(&Printer::on_timer,\n                                    this,\n                                    std::placeholders::_1));\n    }\n\nprivate:\n    void on_timer(const boost::system::error_code& ec)\n    {\n        if (ec)\n        {\n            std::println(\"Printer::on_timer 被取消：{}\", ec.message());\n            return;\n        }\n\n        std::println(\"Printer::on_timer：2 秒到了\");\n    }\n\nprivate:\n    \u002F\u002F 创建定时器，并设置到期时间。\n    boost::asio::steady_timer timer_;\n};\n\nint main()\n{\n    \u002F\u002F 程序从 main 函数开始执行，下面的语句会按顺序运行。\n    \u002F\u002F io_context 是 Asio 的事件循环对象，异步任务需要靠它调度。\n    boost::asio::io_context io;\n\n    Printer printer(io);\n\n    std::println(\"main：准备调用 io.run()\");\n\n    io.run();\n\n    std::println(\"main：io.run() 返回\");\n\n    return 0;\n}\n",[23,2538,2539,2545,2551,2557,2563,2569,2573,2581,2585,2590,2618,2644,2648,2663,2667,2672,2697,2704,2714,2718,2722,2727,2754,2758,2765,2770,2790,2797,2802,2806,2821,2825,2829,2833,2837,2848,2853,2857,2865,2869,2873,2877,2887,2891,2902,2906,2920,2924,2932,2936,2951,2955,2963],{"__ignoreMap":62},[66,2540,2541,2543],{"class":68,"line":69},[66,2542,73],{"class":72},[66,2544,77],{"class":76},[66,2546,2547,2549],{"class":68,"line":80},[66,2548,73],{"class":72},[66,2550,515],{"class":76},[66,2552,2553,2555],{"class":68,"line":88},[66,2554,73],{"class":72},[66,2556,85],{"class":76},[66,2558,2559,2561],{"class":68,"line":96},[66,2560,73],{"class":72},[66,2562,528],{"class":76},[66,2564,2565,2567],{"class":68,"line":103},[66,2566,73],{"class":72},[66,2568,93],{"class":76},[66,2570,2571],{"class":68,"line":117},[66,2572,100],{"emptyLinePlaceholder":99},[66,2574,2575,2578],{"class":68,"line":123},[66,2576,2577],{"class":72},"class",[66,2579,2580],{"class":109}," Printer\n",[66,2582,2583],{"class":68,"line":130},[66,2584,120],{"class":113},[66,2586,2587],{"class":68,"line":136},[66,2588,2589],{"class":72},"public:\n",[66,2591,2592,2595,2598,2600,2603,2605,2607,2609,2611,2613,2616],{"class":68,"line":151},[66,2593,2594],{"class":72},"    explicit",[66,2596,2597],{"class":109}," Printer",[66,2599,193],{"class":113},[66,2601,2602],{"class":109},"boost",[66,2604,142],{"class":113},[66,2606,145],{"class":109},[66,2608,142],{"class":113},[66,2610,404],{"class":109},[66,2612,566],{"class":72},[66,2614,2615],{"class":569}," io",[66,2617,429],{"class":113},[66,2619,2620,2623,2626,2628,2630,2632,2634,2636,2638,2640,2642],{"class":68,"line":156},[66,2621,2622],{"class":113},"        : ",[66,2624,2625],{"class":109},"timer_",[66,2627,177],{"class":113},[66,2629,180],{"class":109},[66,2631,142],{"class":113},[66,2633,185],{"class":109},[66,2635,142],{"class":113},[66,2637,190],{"class":109},[66,2639,193],{"class":113},[66,2641,197],{"class":196},[66,2643,1735],{"class":113},[66,2645,2646],{"class":68,"line":162},[66,2647,589],{"class":113},[66,2649,2650,2652,2654,2656,2658,2661],{"class":68,"line":203},[66,2651,594],{"class":109},[66,2653,142],{"class":113},[66,2655,216],{"class":109},[66,2657,193],{"class":113},[66,2659,2660],{"class":76},"\"Printer 构造：注册 2 秒定时器\"",[66,2662,224],{"class":113},[66,2664,2665],{"class":68,"line":208},[66,2666,100],{"emptyLinePlaceholder":99},[66,2668,2669],{"class":68,"line":227},[66,2670,2671],{"class":126},"        \u002F\u002F 注册异步等待：这一行不会阻塞，回调会在定时器到期后执行。\n",[66,2673,2674,2677,2679,2681,2683,2685,2687,2689,2691,2694],{"class":68,"line":232},[66,2675,2676],{"class":113},"        timer_.",[66,2678,762],{"class":109},[66,2680,193],{"class":113},[66,2682,180],{"class":109},[66,2684,142],{"class":113},[66,2686,771],{"class":109},[66,2688,193],{"class":113},[66,2690,566],{"class":72},[66,2692,2693],{"class":109},"Printer",[66,2695,2696],{"class":113},"::on_timer,\n",[66,2698,2699,2702],{"class":68,"line":238},[66,2700,2701],{"class":196},"                                    this",[66,2703,1849],{"class":113},[66,2705,2706,2708,2710,2712],{"class":68,"line":250},[66,2707,2040],{"class":109},[66,2709,142],{"class":113},[66,2711,781],{"class":109},[66,2713,784],{"class":113},[66,2715,2716],{"class":68,"line":255},[66,2717,624],{"class":113},[66,2719,2720],{"class":68,"line":271},[66,2721,100],{"emptyLinePlaceholder":99},[66,2723,2724],{"class":68,"line":276},[66,2725,2726],{"class":72},"private:\n",[66,2728,2729,2732,2734,2736,2738,2740,2742,2744,2746,2748,2750,2752],{"class":68,"line":288},[66,2730,2731],{"class":72},"    void",[66,2733,545],{"class":109},[66,2735,193],{"class":113},[66,2737,550],{"class":72},[66,2739,553],{"class":109},[66,2741,142],{"class":113},[66,2743,558],{"class":109},[66,2745,142],{"class":113},[66,2747,563],{"class":109},[66,2749,566],{"class":72},[66,2751,570],{"class":569},[66,2753,429],{"class":113},[66,2755,2756],{"class":68,"line":684},[66,2757,589],{"class":113},[66,2759,2760,2763],{"class":68,"line":689},[66,2761,2762],{"class":72},"        if",[66,2764,584],{"class":113},[66,2766,2767],{"class":68,"line":694},[66,2768,2769],{"class":113},"        {\n",[66,2771,2772,2775,2777,2779,2781,2784,2786,2788],{"class":68,"line":725},[66,2773,2774],{"class":109},"            std",[66,2776,142],{"class":113},[66,2778,216],{"class":109},[66,2780,193],{"class":113},[66,2782,2783],{"class":76},"\"Printer::on_timer 被取消：{}\"",[66,2785,606],{"class":113},[66,2787,609],{"class":109},[66,2789,612],{"class":113},[66,2791,2792,2795],{"class":68,"line":730},[66,2793,2794],{"class":72},"            return",[66,2796,285],{"class":113},[66,2798,2799],{"class":68,"line":746},[66,2800,2801],{"class":113},"        }\n",[66,2803,2804],{"class":68,"line":751},[66,2805,100],{"emptyLinePlaceholder":99},[66,2807,2808,2810,2812,2814,2816,2819],{"class":68,"line":757},[66,2809,594],{"class":109},[66,2811,142],{"class":113},[66,2813,216],{"class":109},[66,2815,193],{"class":113},[66,2817,2818],{"class":76},"\"Printer::on_timer：2 秒到了\"",[66,2820,224],{"class":113},[66,2822,2823],{"class":68,"line":787},[66,2824,624],{"class":113},[66,2826,2827],{"class":68,"line":792},[66,2828,100],{"emptyLinePlaceholder":99},[66,2830,2831],{"class":68,"line":808},[66,2832,2726],{"class":72},[66,2834,2835],{"class":68,"line":824},[66,2836,159],{"class":126},[66,2838,2839,2841,2843,2845],{"class":68,"line":829},[66,2840,139],{"class":109},[66,2842,142],{"class":113},[66,2844,145],{"class":109},[66,2846,2847],{"class":113},"::steady_timer timer_;\n",[66,2849,2850],{"class":68,"line":840},[66,2851,2852],{"class":113},"};\n",[66,2854,2855],{"class":68,"line":845},[66,2856,100],{"emptyLinePlaceholder":99},[66,2858,2859,2861,2863],{"class":68,"line":861},[66,2860,106],{"class":72},[66,2862,110],{"class":109},[66,2864,114],{"class":113},[66,2866,2867],{"class":68,"line":866},[66,2868,120],{"class":113},[66,2870,2871],{"class":68,"line":875},[66,2872,127],{"class":126},[66,2874,2875],{"class":68,"line":1548},[66,2876,133],{"class":126},[66,2878,2879,2881,2883,2885],{"class":68,"line":1553},[66,2880,139],{"class":109},[66,2882,142],{"class":113},[66,2884,145],{"class":109},[66,2886,148],{"class":113},[66,2888,2889],{"class":68,"line":1576},[66,2890,100],{"emptyLinePlaceholder":99},[66,2892,2893,2896,2899],{"class":68,"line":1581},[66,2894,2895],{"class":113},"    Printer ",[66,2897,2898],{"class":109},"printer",[66,2900,2901],{"class":113},"(io);\n",[66,2903,2904],{"class":68,"line":1598},[66,2905,100],{"emptyLinePlaceholder":99},[66,2907,2908,2910,2912,2914,2916,2918],{"class":68,"line":1603},[66,2909,211],{"class":109},[66,2911,142],{"class":113},[66,2913,216],{"class":109},[66,2915,193],{"class":113},[66,2917,819],{"class":76},[66,2919,224],{"class":113},[66,2921,2922],{"class":68,"line":1612},[66,2923,100],{"emptyLinePlaceholder":99},[66,2925,2926,2928,2930],{"class":68,"line":2219},[66,2927,832],{"class":113},[66,2929,835],{"class":109},[66,2931,247],{"class":113},[66,2933,2934],{"class":68,"line":2231},[66,2935,100],{"emptyLinePlaceholder":99},[66,2937,2938,2940,2942,2944,2946,2949],{"class":68,"line":2240},[66,2939,211],{"class":109},[66,2941,142],{"class":113},[66,2943,216],{"class":109},[66,2945,193],{"class":113},[66,2947,2948],{"class":76},"\"main：io.run() 返回\"",[66,2950,224],{"class":113},[66,2952,2953],{"class":68,"line":2248},[66,2954,100],{"emptyLinePlaceholder":99},[66,2956,2957,2959,2961],{"class":68,"line":2253},[66,2958,279],{"class":72},[66,2960,282],{"class":196},[66,2962,285],{"class":113},[66,2964,2965],{"class":68,"line":2262},[66,2966,291],{"class":113},[15,2968,2969,298],{},[295,2970,297],{},[47,2972,301],{"id":2973},"运行输出与时间顺序-4",[15,2975,887],{},[57,2977,2980],{"className":2978,"code":2979,"language":307,"meta":62},[305],"Printer 构造：注册 2 秒定时器\nmain：准备调用 io.run()\n",[23,2981,2979],{"__ignoreMap":62},[15,2983,2984],{},"约 2 秒后输出：",[57,2986,2989],{"className":2987,"code":2988,"language":307,"meta":62},[305],"Printer::on_timer：2 秒到了\nmain：io.run() 返回\n",[23,2990,2988],{"__ignoreMap":62},[15,2992,321],{},[57,2994,2997],{"className":2995,"code":2996,"language":307,"meta":62},[305],"Printer 构造：注册 2 秒定时器\nmain：准备调用 io.run()\nPrinter::on_timer：2 秒到了\nmain：io.run() 返回\n",[23,2998,2996],{"__ignoreMap":62},[47,3000,3001],{"id":3001},"构造函数初始化列表说明",[15,3003,3004],{},"这段：",[57,3006,3008],{"className":59,"code":3007,"language":61,"meta":62,"style":62},"explicit Printer(boost::asio::io_context& io)\n    : timer_(io, std::chrono::seconds(2))\n{\n}\n",[23,3009,3010,3033,3058,3062],{"__ignoreMap":62},[66,3011,3012,3015,3017,3019,3021,3023,3025,3028,3030],{"class":68,"line":69},[66,3013,3014],{"class":72},"explicit",[66,3016,2597],{"class":109},[66,3018,193],{"class":113},[66,3020,2602],{"class":109},[66,3022,142],{"class":113},[66,3024,145],{"class":109},[66,3026,3027],{"class":113},"::io_context",[66,3029,566],{"class":72},[66,3031,3032],{"class":113}," io)\n",[66,3034,3035,3038,3040,3042,3044,3046,3048,3050,3052,3054,3056],{"class":68,"line":80},[66,3036,3037],{"class":113},"    : ",[66,3039,2625],{"class":109},[66,3041,177],{"class":113},[66,3043,180],{"class":109},[66,3045,142],{"class":113},[66,3047,185],{"class":109},[66,3049,142],{"class":113},[66,3051,190],{"class":109},[66,3053,193],{"class":113},[66,3055,197],{"class":196},[66,3057,1735],{"class":113},[66,3059,3060],{"class":68,"line":88},[66,3061,120],{"class":113},[66,3063,3064],{"class":68,"line":96},[66,3065,291],{"class":113},[15,3067,3068],{},"冒号后面叫“构造函数初始化列表”。",[15,3070,3071,3072,448],{},"它的作用是：在进入构造函数大括号之前，直接构造成员变量 ",[23,3073,2625],{},[15,3075,3076,3077,3080,3081,448],{},"为什么这里必须这么写？因为 ",[23,3078,3079],{},"boost::asio::steady_timer"," 没有一个适合你先默认构造、再赋值的简单写法。它需要在构造时就知道自己属于哪个 ",[23,3082,404],{},[47,3084,3085],{"id":3085},"成员函数绑定说明",[15,3087,1698],{},[57,3089,3091],{"className":59,"code":3090,"language":61,"meta":62,"style":62},"timer_.async_wait(std::bind(&Printer::on_timer,\n                            this,\n                            std::placeholders::_1));\n",[23,3092,3093,3116,3123],{"__ignoreMap":62},[66,3094,3095,3098,3100,3102,3104,3106,3108,3110,3112,3114],{"class":68,"line":69},[66,3096,3097],{"class":113},"timer_.",[66,3099,762],{"class":109},[66,3101,193],{"class":113},[66,3103,180],{"class":109},[66,3105,142],{"class":113},[66,3107,771],{"class":109},[66,3109,193],{"class":113},[66,3111,566],{"class":72},[66,3113,2693],{"class":109},[66,3115,2696],{"class":113},[66,3117,3118,3121],{"class":68,"line":80},[66,3119,3120],{"class":196},"                            this",[66,3122,1849],{"class":113},[66,3124,3125,3128,3130,3132],{"class":68,"line":88},[66,3126,3127],{"class":109},"                            std",[66,3129,142],{"class":113},[66,3131,781],{"class":109},[66,3133,784],{"class":113},[15,3135,3136],{},"含义是：",[57,3138,3141],{"className":3139,"code":3140,"language":307,"meta":62},[305],"定时器到期后，调用 this->on_timer(ec)。\n",[23,3142,3140],{"__ignoreMap":62},[15,3144,3145,3146,3149],{},"为什么要写 ",[23,3147,3148],{},"&Printer::on_timer","？",[15,3151,3152,3153,3155],{},"因为 ",[23,3154,1017],{}," 是成员函数，不是普通全局函数。成员函数必须依赖某个对象才能调用。",[15,3157,3158,3159,3149],{},"为什么要传 ",[23,3160,3161],{},"this",[15,3163,3152,3164,3166,3167,3169],{},[23,3165,3161],{}," 表示当前这个 ",[23,3168,2693],{}," 对象。",[47,3171,3172],{"id":3172},"易错点",[15,3174,3175],{},"不要写成：",[57,3177,3179],{"className":59,"code":3178,"language":61,"meta":62,"style":62},"std::bind(on_timer, std::placeholders::_1)\n",[23,3180,3181],{"__ignoreMap":62},[66,3182,3183,3185,3187,3189,3191,3193,3195,3197],{"class":68,"line":69},[66,3184,180],{"class":109},[66,3186,142],{"class":113},[66,3188,771],{"class":109},[66,3190,774],{"class":113},[66,3192,180],{"class":109},[66,3194,142],{"class":113},[66,3196,781],{"class":109},[66,3198,3199],{"class":113},"::_1)\n",[15,3201,3152,3202,3204],{},[23,3203,1017],{}," 是成员函数，不是普通函数。",[15,3206,3207,3208,3210],{},"也不要漏掉 ",[23,3209,3161],{},"：",[57,3212,3214],{"className":59,"code":3213,"language":61,"meta":62,"style":62},"std::bind(&Printer::on_timer, std::placeholders::_1)\n",[23,3215,3216],{"__ignoreMap":62},[66,3217,3218,3220,3222,3224,3226,3228,3230,3233,3235,3237,3239],{"class":68,"line":69},[66,3219,180],{"class":109},[66,3221,142],{"class":113},[66,3223,771],{"class":109},[66,3225,193],{"class":113},[66,3227,566],{"class":72},[66,3229,2693],{"class":109},[66,3231,3232],{"class":113},"::on_timer, ",[66,3234,180],{"class":109},[66,3236,142],{"class":113},[66,3238,781],{"class":109},[66,3240,3199],{"class":113},[15,3242,3243,3244,448],{},"这样不知道要调用哪个对象的 ",[23,3245,3246],{},"on_timer()",[35,3248],{},[38,3250,3252],{"id":3251},"示例-6类里写两个定时器","示例 6：类里写两个定时器",[47,3254,49],{"id":3255},"程序目标-5",[15,3257,3258],{},"类里同时维护两个 timer：",[468,3260,3261,3267,3273],{},[471,3262,3263,3266],{},[23,3264,3265],{},"timer1_"," 1 秒后执行；",[471,3268,3269,3272],{},[23,3270,3271],{},"timer2_"," 3 秒后执行；",[471,3274,3275],{},"用这个例子看清楚“两个异步任务不等于两个线程”。",[47,3277,55],{"id":3278},"完整代码-5",[57,3280,3282],{"className":59,"code":3281,"language":61,"meta":62,"style":62},"#include \u003Cboost\u002Fasio.hpp>\n#include \u003Cboost\u002Fsystem\u002Ferror_code.hpp>\n#include \u003Cchrono>\n#include \u003Cfunctional>\n#include \u003Cprint>\n\nclass TwoTimers\n{\npublic:\n    explicit TwoTimers(boost::asio::io_context& io)\n        : timer1_(io, std::chrono::seconds(1)),\n          timer2_(io, std::chrono::seconds(3))\n    {\n        std::println(\"TwoTimers 构造：注册 timer1 和 timer2\");\n\n        \u002F\u002F 注册异步等待：这一行不会阻塞，回调会在定时器到期后执行。\n        timer1_.async_wait(std::bind(&TwoTimers::on_timer1,\n                                     this,\n                                     std::placeholders::_1));\n\n        timer2_.async_wait(std::bind(&TwoTimers::on_timer2,\n                                     this,\n                                     std::placeholders::_1));\n    }\n\nprivate:\n    void on_timer1(const boost::system::error_code& ec)\n    {\n        if (ec)\n        {\n            std::println(\"timer1 取消：{}\", ec.message());\n            return;\n        }\n\n        std::println(\"timer1：1 秒到了\");\n    }\n\n    void on_timer2(const boost::system::error_code& ec)\n    {\n        if (ec)\n        {\n            std::println(\"timer2 取消：{}\", ec.message());\n            return;\n        }\n\n        std::println(\"timer2：3 秒到了\");\n    }\n\nprivate:\n    \u002F\u002F 创建定时器，并设置到期时间。\n    boost::asio::steady_timer timer1_;\n    boost::asio::steady_timer timer2_;\n};\n\nint main()\n{\n    \u002F\u002F 程序从 main 函数开始执行，下面的语句会按顺序运行。\n    \u002F\u002F io_context 是 Asio 的事件循环对象，异步任务需要靠它调度。\n    boost::asio::io_context io;\n    TwoTimers app(io);\n\n    std::println(\"main：调用 io.run()\");\n\n    io.run();\n\n    std::println(\"main：两个定时器都执行完，io.run() 返回\");\n\n    return 0;\n}\n",[23,3283,3284,3290,3296,3302,3308,3314,3318,3325,3329,3333,3358,3383,3406,3410,3425,3429,3433,3458,3465,3476,3480,3504,3510,3520,3524,3528,3532,3559,3563,3569,3573,3592,3598,3602,3606,3621,3625,3629,3656,3660,3666,3670,3689,3695,3699,3703,3718,3722,3726,3730,3734,3745,3756,3760,3764,3772,3776,3780,3785,3796,3807,3812,3827,3832,3841,3846,3862,3867,3876],{"__ignoreMap":62},[66,3285,3286,3288],{"class":68,"line":69},[66,3287,73],{"class":72},[66,3289,77],{"class":76},[66,3291,3292,3294],{"class":68,"line":80},[66,3293,73],{"class":72},[66,3295,515],{"class":76},[66,3297,3298,3300],{"class":68,"line":88},[66,3299,73],{"class":72},[66,3301,85],{"class":76},[66,3303,3304,3306],{"class":68,"line":96},[66,3305,73],{"class":72},[66,3307,528],{"class":76},[66,3309,3310,3312],{"class":68,"line":103},[66,3311,73],{"class":72},[66,3313,93],{"class":76},[66,3315,3316],{"class":68,"line":117},[66,3317,100],{"emptyLinePlaceholder":99},[66,3319,3320,3322],{"class":68,"line":123},[66,3321,2577],{"class":72},[66,3323,3324],{"class":109}," TwoTimers\n",[66,3326,3327],{"class":68,"line":130},[66,3328,120],{"class":113},[66,3330,3331],{"class":68,"line":136},[66,3332,2589],{"class":72},[66,3334,3335,3337,3340,3342,3344,3346,3348,3350,3352,3354,3356],{"class":68,"line":151},[66,3336,2594],{"class":72},[66,3338,3339],{"class":109}," TwoTimers",[66,3341,193],{"class":113},[66,3343,2602],{"class":109},[66,3345,142],{"class":113},[66,3347,145],{"class":109},[66,3349,142],{"class":113},[66,3351,404],{"class":109},[66,3353,566],{"class":72},[66,3355,2615],{"class":569},[66,3357,429],{"class":113},[66,3359,3360,3362,3364,3366,3368,3370,3372,3374,3376,3378,3380],{"class":68,"line":156},[66,3361,2622],{"class":113},[66,3363,3265],{"class":109},[66,3365,177],{"class":113},[66,3367,180],{"class":109},[66,3369,142],{"class":113},[66,3371,185],{"class":109},[66,3373,142],{"class":113},[66,3375,190],{"class":109},[66,3377,193],{"class":113},[66,3379,1363],{"class":196},[66,3381,3382],{"class":113},")),\n",[66,3384,3385,3388,3390,3392,3394,3396,3398,3400,3402,3404],{"class":68,"line":162},[66,3386,3387],{"class":109},"          timer2_",[66,3389,177],{"class":113},[66,3391,180],{"class":109},[66,3393,142],{"class":113},[66,3395,185],{"class":109},[66,3397,142],{"class":113},[66,3399,190],{"class":109},[66,3401,193],{"class":113},[66,3403,1394],{"class":196},[66,3405,1735],{"class":113},[66,3407,3408],{"class":68,"line":203},[66,3409,589],{"class":113},[66,3411,3412,3414,3416,3418,3420,3423],{"class":68,"line":208},[66,3413,594],{"class":109},[66,3415,142],{"class":113},[66,3417,216],{"class":109},[66,3419,193],{"class":113},[66,3421,3422],{"class":76},"\"TwoTimers 构造：注册 timer1 和 timer2\"",[66,3424,224],{"class":113},[66,3426,3427],{"class":68,"line":227},[66,3428,100],{"emptyLinePlaceholder":99},[66,3430,3431],{"class":68,"line":232},[66,3432,2671],{"class":126},[66,3434,3435,3438,3440,3442,3444,3446,3448,3450,3452,3455],{"class":68,"line":238},[66,3436,3437],{"class":113},"        timer1_.",[66,3439,762],{"class":109},[66,3441,193],{"class":113},[66,3443,180],{"class":109},[66,3445,142],{"class":113},[66,3447,771],{"class":109},[66,3449,193],{"class":113},[66,3451,566],{"class":72},[66,3453,3454],{"class":109},"TwoTimers",[66,3456,3457],{"class":113},"::on_timer1,\n",[66,3459,3460,3463],{"class":68,"line":250},[66,3461,3462],{"class":196},"                                     this",[66,3464,1849],{"class":113},[66,3466,3467,3470,3472,3474],{"class":68,"line":255},[66,3468,3469],{"class":109},"                                     std",[66,3471,142],{"class":113},[66,3473,781],{"class":109},[66,3475,784],{"class":113},[66,3477,3478],{"class":68,"line":271},[66,3479,100],{"emptyLinePlaceholder":99},[66,3481,3482,3485,3487,3489,3491,3493,3495,3497,3499,3501],{"class":68,"line":276},[66,3483,3484],{"class":113},"        timer2_.",[66,3486,762],{"class":109},[66,3488,193],{"class":113},[66,3490,180],{"class":109},[66,3492,142],{"class":113},[66,3494,771],{"class":109},[66,3496,193],{"class":113},[66,3498,566],{"class":72},[66,3500,3454],{"class":109},[66,3502,3503],{"class":113},"::on_timer2,\n",[66,3505,3506,3508],{"class":68,"line":288},[66,3507,3462],{"class":196},[66,3509,1849],{"class":113},[66,3511,3512,3514,3516,3518],{"class":68,"line":684},[66,3513,3469],{"class":109},[66,3515,142],{"class":113},[66,3517,781],{"class":109},[66,3519,784],{"class":113},[66,3521,3522],{"class":68,"line":689},[66,3523,624],{"class":113},[66,3525,3526],{"class":68,"line":694},[66,3527,100],{"emptyLinePlaceholder":99},[66,3529,3530],{"class":68,"line":725},[66,3531,2726],{"class":72},[66,3533,3534,3536,3539,3541,3543,3545,3547,3549,3551,3553,3555,3557],{"class":68,"line":730},[66,3535,2731],{"class":72},[66,3537,3538],{"class":109}," on_timer1",[66,3540,193],{"class":113},[66,3542,550],{"class":72},[66,3544,553],{"class":109},[66,3546,142],{"class":113},[66,3548,558],{"class":109},[66,3550,142],{"class":113},[66,3552,563],{"class":109},[66,3554,566],{"class":72},[66,3556,570],{"class":569},[66,3558,429],{"class":113},[66,3560,3561],{"class":68,"line":746},[66,3562,589],{"class":113},[66,3564,3565,3567],{"class":68,"line":751},[66,3566,2762],{"class":72},[66,3568,584],{"class":113},[66,3570,3571],{"class":68,"line":757},[66,3572,2769],{"class":113},[66,3574,3575,3577,3579,3581,3583,3586,3588,3590],{"class":68,"line":787},[66,3576,2774],{"class":109},[66,3578,142],{"class":113},[66,3580,216],{"class":109},[66,3582,193],{"class":113},[66,3584,3585],{"class":76},"\"timer1 取消：{}\"",[66,3587,606],{"class":113},[66,3589,609],{"class":109},[66,3591,612],{"class":113},[66,3593,3594,3596],{"class":68,"line":792},[66,3595,2794],{"class":72},[66,3597,285],{"class":113},[66,3599,3600],{"class":68,"line":808},[66,3601,2801],{"class":113},[66,3603,3604],{"class":68,"line":824},[66,3605,100],{"emptyLinePlaceholder":99},[66,3607,3608,3610,3612,3614,3616,3619],{"class":68,"line":829},[66,3609,594],{"class":109},[66,3611,142],{"class":113},[66,3613,216],{"class":109},[66,3615,193],{"class":113},[66,3617,3618],{"class":76},"\"timer1：1 秒到了\"",[66,3620,224],{"class":113},[66,3622,3623],{"class":68,"line":840},[66,3624,624],{"class":113},[66,3626,3627],{"class":68,"line":845},[66,3628,100],{"emptyLinePlaceholder":99},[66,3630,3631,3633,3636,3638,3640,3642,3644,3646,3648,3650,3652,3654],{"class":68,"line":861},[66,3632,2731],{"class":72},[66,3634,3635],{"class":109}," on_timer2",[66,3637,193],{"class":113},[66,3639,550],{"class":72},[66,3641,553],{"class":109},[66,3643,142],{"class":113},[66,3645,558],{"class":109},[66,3647,142],{"class":113},[66,3649,563],{"class":109},[66,3651,566],{"class":72},[66,3653,570],{"class":569},[66,3655,429],{"class":113},[66,3657,3658],{"class":68,"line":866},[66,3659,589],{"class":113},[66,3661,3662,3664],{"class":68,"line":875},[66,3663,2762],{"class":72},[66,3665,584],{"class":113},[66,3667,3668],{"class":68,"line":1548},[66,3669,2769],{"class":113},[66,3671,3672,3674,3676,3678,3680,3683,3685,3687],{"class":68,"line":1553},[66,3673,2774],{"class":109},[66,3675,142],{"class":113},[66,3677,216],{"class":109},[66,3679,193],{"class":113},[66,3681,3682],{"class":76},"\"timer2 取消：{}\"",[66,3684,606],{"class":113},[66,3686,609],{"class":109},[66,3688,612],{"class":113},[66,3690,3691,3693],{"class":68,"line":1576},[66,3692,2794],{"class":72},[66,3694,285],{"class":113},[66,3696,3697],{"class":68,"line":1581},[66,3698,2801],{"class":113},[66,3700,3701],{"class":68,"line":1598},[66,3702,100],{"emptyLinePlaceholder":99},[66,3704,3705,3707,3709,3711,3713,3716],{"class":68,"line":1603},[66,3706,594],{"class":109},[66,3708,142],{"class":113},[66,3710,216],{"class":109},[66,3712,193],{"class":113},[66,3714,3715],{"class":76},"\"timer2：3 秒到了\"",[66,3717,224],{"class":113},[66,3719,3720],{"class":68,"line":1612},[66,3721,624],{"class":113},[66,3723,3724],{"class":68,"line":2219},[66,3725,100],{"emptyLinePlaceholder":99},[66,3727,3728],{"class":68,"line":2231},[66,3729,2726],{"class":72},[66,3731,3732],{"class":68,"line":2240},[66,3733,159],{"class":126},[66,3735,3736,3738,3740,3742],{"class":68,"line":2248},[66,3737,139],{"class":109},[66,3739,142],{"class":113},[66,3741,145],{"class":109},[66,3743,3744],{"class":113},"::steady_timer timer1_;\n",[66,3746,3747,3749,3751,3753],{"class":68,"line":2253},[66,3748,139],{"class":109},[66,3750,142],{"class":113},[66,3752,145],{"class":109},[66,3754,3755],{"class":113},"::steady_timer timer2_;\n",[66,3757,3758],{"class":68,"line":2262},[66,3759,2852],{"class":113},[66,3761,3762],{"class":68,"line":2267},[66,3763,100],{"emptyLinePlaceholder":99},[66,3765,3766,3768,3770],{"class":68,"line":2282},[66,3767,106],{"class":72},[66,3769,110],{"class":109},[66,3771,114],{"class":113},[66,3773,3774],{"class":68,"line":2287},[66,3775,120],{"class":113},[66,3777,3778],{"class":68,"line":2296},[66,3779,127],{"class":126},[66,3781,3783],{"class":68,"line":3782},58,[66,3784,133],{"class":126},[66,3786,3788,3790,3792,3794],{"class":68,"line":3787},59,[66,3789,139],{"class":109},[66,3791,142],{"class":113},[66,3793,145],{"class":109},[66,3795,148],{"class":113},[66,3797,3799,3802,3805],{"class":68,"line":3798},60,[66,3800,3801],{"class":113},"    TwoTimers ",[66,3803,3804],{"class":109},"app",[66,3806,2901],{"class":113},[66,3808,3810],{"class":68,"line":3809},61,[66,3811,100],{"emptyLinePlaceholder":99},[66,3813,3815,3817,3819,3821,3823,3825],{"class":68,"line":3814},62,[66,3816,211],{"class":109},[66,3818,142],{"class":113},[66,3820,216],{"class":109},[66,3822,193],{"class":113},[66,3824,1543],{"class":76},[66,3826,224],{"class":113},[66,3828,3830],{"class":68,"line":3829},63,[66,3831,100],{"emptyLinePlaceholder":99},[66,3833,3835,3837,3839],{"class":68,"line":3834},64,[66,3836,832],{"class":113},[66,3838,835],{"class":109},[66,3840,247],{"class":113},[66,3842,3844],{"class":68,"line":3843},65,[66,3845,100],{"emptyLinePlaceholder":99},[66,3847,3849,3851,3853,3855,3857,3860],{"class":68,"line":3848},66,[66,3850,211],{"class":109},[66,3852,142],{"class":113},[66,3854,216],{"class":109},[66,3856,193],{"class":113},[66,3858,3859],{"class":76},"\"main：两个定时器都执行完，io.run() 返回\"",[66,3861,224],{"class":113},[66,3863,3865],{"class":68,"line":3864},67,[66,3866,100],{"emptyLinePlaceholder":99},[66,3868,3870,3872,3874],{"class":68,"line":3869},68,[66,3871,279],{"class":72},[66,3873,282],{"class":196},[66,3875,285],{"class":113},[66,3877,3879],{"class":68,"line":3878},69,[66,3880,291],{"class":113},[15,3882,3883,298],{},[295,3884,297],{},[47,3886,301],{"id":3887},"运行输出与时间顺序-5",[15,3889,887],{},[57,3891,3894],{"className":3892,"code":3893,"language":307,"meta":62},[305],"TwoTimers 构造：注册 timer1 和 timer2\nmain：调用 io.run()\n",[23,3895,3893],{"__ignoreMap":62},[15,3897,2316],{},[57,3899,3902],{"className":3900,"code":3901,"language":307,"meta":62},[305],"timer1：1 秒到了\n",[23,3903,3901],{"__ignoreMap":62},[15,3905,3906],{},"约 3 秒后：",[57,3908,3911],{"className":3909,"code":3910,"language":307,"meta":62},[305],"timer2：3 秒到了\nmain：两个定时器都执行完，io.run() 返回\n",[23,3912,3910],{"__ignoreMap":62},[15,3914,321],{},[57,3916,3919],{"className":3917,"code":3918,"language":307,"meta":62},[305],"TwoTimers 构造：注册 timer1 和 timer2\nmain：调用 io.run()\ntimer1：1 秒到了\ntimer2：3 秒到了\nmain：两个定时器都执行完，io.run() 返回\n",[23,3920,3918],{"__ignoreMap":62},[47,3922,330],{"id":3923},"本示例需要注意的点-4",[15,3925,3926,1667,3928,3930],{},[23,3927,3265],{},[23,3929,3271],{}," 是两个异步任务，但本例仍然只有一个线程。",[15,3932,3933],{},"因为只有主线程调用了：",[57,3935,3936],{"className":59,"code":899,"language":61,"meta":62,"style":62},[23,3937,3938],{"__ignoreMap":62},[66,3939,3940,3942,3944],{"class":68,"line":69},[66,3941,906],{"class":113},[66,3943,835],{"class":109},[66,3945,247],{"class":113},[15,3947,3948],{},"所以两个回调都在主线程里执行，不会并行执行。",[35,3950],{},[38,3952,3954,3955],{"id":3953},"示例-7两个线程同时运行同一个-io_context","示例 7：两个线程同时运行同一个 ",[23,3956,404],{},[47,3958,49],{"id":3959},"程序目标-6",[15,3961,3962,3963,3965],{},"这次让两个线程都调用 ",[23,3964,484],{},"，观察回调可能由不同线程执行。",[15,3967,3968],{},"这个例子用于理解官方 Timer.5 那类程序：",[57,3970,3973],{"className":3971,"code":3972,"language":307,"meta":62},[305],"多个线程 run 同一个 io_context\n回调函数可能分配给任意一个正在 run 的线程执行\n",[23,3974,3972],{"__ignoreMap":62},[47,3976,55],{"id":3977},"完整代码-6",[57,3979,3981],{"className":59,"code":3980,"language":61,"meta":62,"style":62},"#include \u003Cboost\u002Fasio.hpp>\n#include \u003Cboost\u002Fsystem\u002Ferror_code.hpp>\n#include \u003Cchrono>\n#include \u003Cfunctional>\n#include \u003Cprint>\n#include \u003Cstring>\n#include \u003Cthread>\n\nvoid print_timer(const boost::system::error_code& ec, const std::string& name)\n{\n    if (ec)\n    {\n        std::println(\"{} 取消：{}\", name, ec.message());\n        return;\n    }\n\n    std::println(\"{} 回调执行，线程 id = {}\", name, std::this_thread::get_id());\n}\n\nvoid run_io(boost::asio::io_context* io, const std::string& thread_name)\n{\n    std::println(\"{} 开始调用 io.run()，线程 id = {}\", thread_name, std::this_thread::get_id());\n\n    io->run();\n\n    std::println(\"{} 的 io.run() 返回\", thread_name);\n}\n\nint main()\n{\n    \u002F\u002F 程序从 main 函数开始执行，下面的语句会按顺序运行。\n    \u002F\u002F io_context 是 Asio 的事件循环对象，异步任务需要靠它调度。\n    boost::asio::io_context io;\n\n    \u002F\u002F 创建定时器，并设置到期时间。\n    boost::asio::steady_timer timer1(io, std::chrono::seconds(1));\n    boost::asio::steady_timer timer2(io, std::chrono::seconds(1));\n\n    \u002F\u002F 注册异步等待：这一行不会阻塞，回调会在定时器到期后执行。\n    timer1.async_wait(std::bind(print_timer,\n                                std::placeholders::_1,\n                                std::string(\"timer1\")));\n\n    timer2.async_wait(std::bind(print_timer,\n                                std::placeholders::_1,\n                                std::string(\"timer2\")));\n\n    std::thread t1(std::bind(run_io, &io, std::string(\"线程1\")));\n    std::thread t2(std::bind(run_io, &io, std::string(\"线程2\")));\n\n    t1.join();\n    t2.join();\n\n    std::println(\"main：两个线程都结束\");\n\n    return 0;\n}\n",[23,3982,3983,3989,3995,4001,4007,4013,4019,4026,4030,4071,4075,4081,4085,4104,4110,4114,4118,4148,4152,4156,4196,4200,4228,4232,4241,4245,4261,4265,4269,4277,4281,4285,4289,4299,4303,4307,4337,4367,4371,4375,4392,4402,4416,4420,4436,4446,4460,4464,4503,4539,4543,4553,4562,4566,4581,4585,4593],{"__ignoreMap":62},[66,3984,3985,3987],{"class":68,"line":69},[66,3986,73],{"class":72},[66,3988,77],{"class":76},[66,3990,3991,3993],{"class":68,"line":80},[66,3992,73],{"class":72},[66,3994,515],{"class":76},[66,3996,3997,3999],{"class":68,"line":88},[66,3998,73],{"class":72},[66,4000,85],{"class":76},[66,4002,4003,4005],{"class":68,"line":96},[66,4004,73],{"class":72},[66,4006,528],{"class":76},[66,4008,4009,4011],{"class":68,"line":103},[66,4010,73],{"class":72},[66,4012,93],{"class":76},[66,4014,4015,4017],{"class":68,"line":117},[66,4016,73],{"class":72},[66,4018,1176],{"class":76},[66,4020,4021,4023],{"class":68,"line":123},[66,4022,73],{"class":72},[66,4024,4025],{"class":76}," \u003Cthread>\n",[66,4027,4028],{"class":68,"line":130},[66,4029,100],{"emptyLinePlaceholder":99},[66,4031,4032,4034,4037,4039,4041,4043,4045,4047,4049,4051,4053,4055,4057,4059,4061,4063,4065,4067,4069],{"class":68,"line":136},[66,4033,447],{"class":72},[66,4035,4036],{"class":109}," print_timer",[66,4038,193],{"class":113},[66,4040,550],{"class":72},[66,4042,553],{"class":109},[66,4044,142],{"class":113},[66,4046,558],{"class":109},[66,4048,142],{"class":113},[66,4050,563],{"class":109},[66,4052,566],{"class":72},[66,4054,570],{"class":569},[66,4056,1207],{"class":113},[66,4058,550],{"class":72},[66,4060,1212],{"class":109},[66,4062,142],{"class":113},[66,4064,1217],{"class":109},[66,4066,566],{"class":72},[66,4068,1222],{"class":569},[66,4070,429],{"class":113},[66,4072,4073],{"class":68,"line":151},[66,4074,120],{"class":113},[66,4076,4077,4079],{"class":68,"line":156},[66,4078,581],{"class":72},[66,4080,584],{"class":113},[66,4082,4083],{"class":68,"line":162},[66,4084,589],{"class":113},[66,4086,4087,4089,4091,4093,4095,4098,4100,4102],{"class":68,"line":203},[66,4088,594],{"class":109},[66,4090,142],{"class":113},[66,4092,216],{"class":109},[66,4094,193],{"class":113},[66,4096,4097],{"class":76},"\"{} 取消：{}\"",[66,4099,1254],{"class":113},[66,4101,609],{"class":109},[66,4103,612],{"class":113},[66,4105,4106,4108],{"class":68,"line":208},[66,4107,617],{"class":72},[66,4109,285],{"class":113},[66,4111,4112],{"class":68,"line":227},[66,4113,624],{"class":113},[66,4115,4116],{"class":68,"line":232},[66,4117,100],{"emptyLinePlaceholder":99},[66,4119,4120,4122,4124,4126,4128,4131,4134,4136,4138,4141,4143,4146],{"class":68,"line":238},[66,4121,211],{"class":109},[66,4123,142],{"class":113},[66,4125,216],{"class":109},[66,4127,193],{"class":113},[66,4129,4130],{"class":76},"\"{} 回调执行，线程 id = {}\"",[66,4132,4133],{"class":113},", name, ",[66,4135,180],{"class":109},[66,4137,142],{"class":113},[66,4139,4140],{"class":109},"this_thread",[66,4142,142],{"class":113},[66,4144,4145],{"class":109},"get_id",[66,4147,612],{"class":113},[66,4149,4150],{"class":68,"line":250},[66,4151,291],{"class":113},[66,4153,4154],{"class":68,"line":255},[66,4155,100],{"emptyLinePlaceholder":99},[66,4157,4158,4160,4163,4165,4167,4169,4171,4173,4175,4177,4179,4181,4183,4185,4187,4189,4191,4194],{"class":68,"line":271},[66,4159,447],{"class":72},[66,4161,4162],{"class":109}," run_io",[66,4164,193],{"class":113},[66,4166,2602],{"class":109},[66,4168,142],{"class":113},[66,4170,145],{"class":109},[66,4172,142],{"class":113},[66,4174,404],{"class":109},[66,4176,1866],{"class":72},[66,4178,2615],{"class":569},[66,4180,1207],{"class":113},[66,4182,550],{"class":72},[66,4184,1212],{"class":109},[66,4186,142],{"class":113},[66,4188,1217],{"class":109},[66,4190,566],{"class":72},[66,4192,4193],{"class":569}," thread_name",[66,4195,429],{"class":113},[66,4197,4198],{"class":68,"line":276},[66,4199,120],{"class":113},[66,4201,4202,4204,4206,4208,4210,4213,4216,4218,4220,4222,4224,4226],{"class":68,"line":288},[66,4203,211],{"class":109},[66,4205,142],{"class":113},[66,4207,216],{"class":109},[66,4209,193],{"class":113},[66,4211,4212],{"class":76},"\"{} 开始调用 io.run()，线程 id = {}\"",[66,4214,4215],{"class":113},", thread_name, ",[66,4217,180],{"class":109},[66,4219,142],{"class":113},[66,4221,4140],{"class":109},[66,4223,142],{"class":113},[66,4225,4145],{"class":109},[66,4227,612],{"class":113},[66,4229,4230],{"class":68,"line":684},[66,4231,100],{"emptyLinePlaceholder":99},[66,4233,4234,4237,4239],{"class":68,"line":689},[66,4235,4236],{"class":113},"    io->",[66,4238,835],{"class":109},[66,4240,247],{"class":113},[66,4242,4243],{"class":68,"line":694},[66,4244,100],{"emptyLinePlaceholder":99},[66,4246,4247,4249,4251,4253,4255,4258],{"class":68,"line":725},[66,4248,211],{"class":109},[66,4250,142],{"class":113},[66,4252,216],{"class":109},[66,4254,193],{"class":113},[66,4256,4257],{"class":76},"\"{} 的 io.run() 返回\"",[66,4259,4260],{"class":113},", thread_name);\n",[66,4262,4263],{"class":68,"line":730},[66,4264,291],{"class":113},[66,4266,4267],{"class":68,"line":746},[66,4268,100],{"emptyLinePlaceholder":99},[66,4270,4271,4273,4275],{"class":68,"line":751},[66,4272,106],{"class":72},[66,4274,110],{"class":109},[66,4276,114],{"class":113},[66,4278,4279],{"class":68,"line":757},[66,4280,120],{"class":113},[66,4282,4283],{"class":68,"line":787},[66,4284,127],{"class":126},[66,4286,4287],{"class":68,"line":792},[66,4288,133],{"class":126},[66,4290,4291,4293,4295,4297],{"class":68,"line":808},[66,4292,139],{"class":109},[66,4294,142],{"class":113},[66,4296,145],{"class":109},[66,4298,148],{"class":113},[66,4300,4301],{"class":68,"line":824},[66,4302,100],{"emptyLinePlaceholder":99},[66,4304,4305],{"class":68,"line":829},[66,4306,159],{"class":126},[66,4308,4309,4311,4313,4315,4317,4319,4321,4323,4325,4327,4329,4331,4333,4335],{"class":68,"line":840},[66,4310,139],{"class":109},[66,4312,142],{"class":113},[66,4314,145],{"class":109},[66,4316,171],{"class":113},[66,4318,1113],{"class":109},[66,4320,177],{"class":113},[66,4322,180],{"class":109},[66,4324,142],{"class":113},[66,4326,185],{"class":109},[66,4328,142],{"class":113},[66,4330,190],{"class":109},[66,4332,193],{"class":113},[66,4334,1363],{"class":196},[66,4336,200],{"class":113},[66,4338,4339,4341,4343,4345,4347,4349,4351,4353,4355,4357,4359,4361,4363,4365],{"class":68,"line":845},[66,4340,139],{"class":109},[66,4342,142],{"class":113},[66,4344,145],{"class":109},[66,4346,171],{"class":113},[66,4348,1119],{"class":109},[66,4350,177],{"class":113},[66,4352,180],{"class":109},[66,4354,142],{"class":113},[66,4356,185],{"class":109},[66,4358,142],{"class":113},[66,4360,190],{"class":109},[66,4362,193],{"class":113},[66,4364,1363],{"class":196},[66,4366,200],{"class":113},[66,4368,4369],{"class":68,"line":861},[66,4370,100],{"emptyLinePlaceholder":99},[66,4372,4373],{"class":68,"line":866},[66,4374,754],{"class":126},[66,4376,4377,4379,4381,4383,4385,4387,4389],{"class":68,"line":875},[66,4378,1424],{"class":113},[66,4380,762],{"class":109},[66,4382,193],{"class":113},[66,4384,180],{"class":109},[66,4386,142],{"class":113},[66,4388,771],{"class":109},[66,4390,4391],{"class":113},"(print_timer,\n",[66,4393,4394,4396,4398,4400],{"class":68,"line":1548},[66,4395,1442],{"class":109},[66,4397,142],{"class":113},[66,4399,781],{"class":109},[66,4401,1449],{"class":113},[66,4403,4404,4406,4408,4410,4412,4414],{"class":68,"line":1553},[66,4405,1442],{"class":109},[66,4407,142],{"class":113},[66,4409,1217],{"class":109},[66,4411,193],{"class":113},[66,4413,1462],{"class":76},[66,4415,1465],{"class":113},[66,4417,4418],{"class":68,"line":1576},[66,4419,100],{"emptyLinePlaceholder":99},[66,4421,4422,4424,4426,4428,4430,4432,4434],{"class":68,"line":1581},[66,4423,1489],{"class":113},[66,4425,762],{"class":109},[66,4427,193],{"class":113},[66,4429,180],{"class":109},[66,4431,142],{"class":113},[66,4433,771],{"class":109},[66,4435,4391],{"class":113},[66,4437,4438,4440,4442,4444],{"class":68,"line":1598},[66,4439,1442],{"class":109},[66,4441,142],{"class":113},[66,4443,781],{"class":109},[66,4445,1449],{"class":113},[66,4447,4448,4450,4452,4454,4456,4458],{"class":68,"line":1603},[66,4449,1442],{"class":109},[66,4451,142],{"class":113},[66,4453,1217],{"class":109},[66,4455,193],{"class":113},[66,4457,1524],{"class":76},[66,4459,1465],{"class":113},[66,4461,4462],{"class":68,"line":1612},[66,4463,100],{"emptyLinePlaceholder":99},[66,4465,4466,4468,4471,4474,4476,4478,4480,4482,4485,4487,4490,4492,4494,4496,4498,4501],{"class":68,"line":2219},[66,4467,211],{"class":109},[66,4469,4470],{"class":113},"::thread ",[66,4472,4473],{"class":109},"t1",[66,4475,193],{"class":113},[66,4477,180],{"class":109},[66,4479,142],{"class":113},[66,4481,771],{"class":109},[66,4483,4484],{"class":113},"(run_io, ",[66,4486,566],{"class":72},[66,4488,4489],{"class":113},"io, ",[66,4491,180],{"class":109},[66,4493,142],{"class":113},[66,4495,1217],{"class":109},[66,4497,193],{"class":113},[66,4499,4500],{"class":76},"\"线程1\"",[66,4502,1465],{"class":113},[66,4504,4505,4507,4509,4512,4514,4516,4518,4520,4522,4524,4526,4528,4530,4532,4534,4537],{"class":68,"line":2231},[66,4506,211],{"class":109},[66,4508,4470],{"class":113},[66,4510,4511],{"class":109},"t2",[66,4513,193],{"class":113},[66,4515,180],{"class":109},[66,4517,142],{"class":113},[66,4519,771],{"class":109},[66,4521,4484],{"class":113},[66,4523,566],{"class":72},[66,4525,4489],{"class":113},[66,4527,180],{"class":109},[66,4529,142],{"class":113},[66,4531,1217],{"class":109},[66,4533,193],{"class":113},[66,4535,4536],{"class":76},"\"线程2\"",[66,4538,1465],{"class":113},[66,4540,4541],{"class":68,"line":2240},[66,4542,100],{"emptyLinePlaceholder":99},[66,4544,4545,4548,4551],{"class":68,"line":2248},[66,4546,4547],{"class":113},"    t1.",[66,4549,4550],{"class":109},"join",[66,4552,247],{"class":113},[66,4554,4555,4558,4560],{"class":68,"line":2253},[66,4556,4557],{"class":113},"    t2.",[66,4559,4550],{"class":109},[66,4561,247],{"class":113},[66,4563,4564],{"class":68,"line":2262},[66,4565,100],{"emptyLinePlaceholder":99},[66,4567,4568,4570,4572,4574,4576,4579],{"class":68,"line":2267},[66,4569,211],{"class":109},[66,4571,142],{"class":113},[66,4573,216],{"class":109},[66,4575,193],{"class":113},[66,4577,4578],{"class":76},"\"main：两个线程都结束\"",[66,4580,224],{"class":113},[66,4582,4583],{"class":68,"line":2282},[66,4584,100],{"emptyLinePlaceholder":99},[66,4586,4587,4589,4591],{"class":68,"line":2287},[66,4588,279],{"class":72},[66,4590,282],{"class":196},[66,4592,285],{"class":113},[66,4594,4595],{"class":68,"line":2296},[66,4596,291],{"class":113},[15,4598,4599,298],{},[295,4600,297],{},[47,4602,301],{"id":4603},"运行输出与时间顺序-6",[15,4605,4606],{},"程序启动后两个线程几乎立刻输出：",[57,4608,4611],{"className":4609,"code":4610,"language":307,"meta":62},[305],"线程1 开始调用 io.run()，线程 id = 140000000000001\n线程2 开始调用 io.run()，线程 id = 140000000000002\n",[23,4612,4610],{"__ignoreMap":62},[15,4614,4615],{},"约 1 秒后，两个 timer 都到期，输出可能类似：",[57,4617,4620],{"className":4618,"code":4619,"language":307,"meta":62},[305],"timer1 回调执行，线程 id = 140000000000001\ntimer2 回调执行，线程 id = 140000000000002\n线程1 的 io.run() 返回\n线程2 的 io.run() 返回\nmain：两个线程都结束\n",[23,4621,4619],{"__ignoreMap":62},[15,4623,4624],{},"也不一定哪个定时器的回调由哪个线程执行，这是不确定的。\n也可能两个回调都被同一个线程执行。线程调度不保证固定。",[47,4626,330],{"id":4627},"本示例需要注意的点-5",[15,4629,4630,4631,4634],{},"这个示例的",[295,4632,4633],{},"重点","是：",[57,4636,4639],{"className":4637,"code":4638,"language":307,"meta":62},[305],"谁调用 io.run()，谁就有可能执行回调函数。\n",[23,4640,4638],{"__ignoreMap":62},[15,4642,4643,4644,4646,4647,4649],{},"不是 ",[23,4645,1113],{}," 固定属于线程 1，",[23,4648,1119],{}," 固定属于线程 2。",[47,4651,4653,4656,4657],{"id":4652},"stdthread-里的-stdbind",[23,4654,4655],{},"std::thread"," 里的 ",[23,4658,32],{},[15,4660,1698],{},[57,4662,4664],{"className":59,"code":4663,"language":61,"meta":62,"style":62},"std::thread t1(std::bind(run_io, &io, std::string(\"线程1\")));\n",[23,4665,4666],{"__ignoreMap":62},[66,4667,4668,4670,4672,4675,4678,4680,4682,4684,4686,4688,4690,4692,4694,4696,4698,4700,4702],{"class":68,"line":69},[66,4669,180],{"class":109},[66,4671,142],{"class":113},[66,4673,4674],{"class":109},"thread",[66,4676,4677],{"class":109}," t1",[66,4679,193],{"class":113},[66,4681,180],{"class":109},[66,4683,142],{"class":113},[66,4685,771],{"class":109},[66,4687,4484],{"class":113},[66,4689,566],{"class":72},[66,4691,4489],{"class":113},[66,4693,180],{"class":109},[66,4695,142],{"class":113},[66,4697,1217],{"class":109},[66,4699,193],{"class":113},[66,4701,4500],{"class":76},[66,4703,1465],{"class":113},[15,4705,4706],{},"意思是创建一个线程，在新线程里执行：",[57,4708,4710],{"className":59,"code":4709,"language":61,"meta":62,"style":62},"run_io(&io, \"线程1\");\n",[23,4711,4712],{"__ignoreMap":62},[66,4713,4714,4717,4719,4721,4723,4725],{"class":68,"line":69},[66,4715,4716],{"class":109},"run_io",[66,4718,193],{"class":113},[66,4720,566],{"class":72},[66,4722,4489],{"class":113},[66,4724,4500],{"class":76},[66,4726,224],{"class":113},[15,4728,4729],{},"这里也没有使用 lambda。",[35,4731],{},[38,4733,4735,4736,4739],{"id":4734},"示例-8多线程下使用-strand-避免回调并发","示例 8：多线程下使用 ",[23,4737,4738],{},"strand"," 避免回调并发",[47,4741,49],{"id":4742},"程序目标-7",[15,4744,4745],{},"如果只有一个线程执行：",[57,4747,4748],{"className":59,"code":899,"language":61,"meta":62,"style":62},[23,4749,4750],{"__ignoreMap":62},[66,4751,4752,4754,4756],{"class":68,"line":69},[66,4753,906],{"class":113},[66,4755,835],{"class":109},[66,4757,247],{"class":113},[15,4759,4760,4761,4763],{},"那么 ",[23,4762,404],{}," 中的 handler 自然只能一个接一个执行。",[15,4765,4766],{},"但是如果有多个线程同时执行同一个：",[57,4768,4769],{"className":59,"code":899,"language":61,"meta":62,"style":62},[23,4770,4771],{"__ignoreMap":62},[66,4772,4773,4775,4777],{"class":68,"line":69},[66,4774,906],{"class":113},[66,4776,835],{"class":109},[66,4778,247],{"class":113},[15,4780,4781],{},"例如：",[57,4783,4786],{"className":4784,"code":4785,"language":307,"meta":62},[305],"线程1 → io.run()\n\n线程2 → io.run()\n",[23,4787,4785],{"__ignoreMap":62},[15,4789,4760,4790,4792],{},[23,4791,404],{}," 中不同的 handler 就可能被不同线程同时取走并执行。",[15,4794,4795],{},"例如两个定时器同时到期：",[57,4797,4800],{"className":4798,"code":4799,"language":307,"meta":62},[305],"线程1 → timer1 的 handler\n\n线程2 → timer2 的 handler\n",[23,4801,4799],{"__ignoreMap":62},[15,4803,4804],{},"如果这两个 handler 都修改同一个普通成员变量：",[57,4806,4808],{"className":59,"code":4807,"language":61,"meta":62,"style":62},"int count_;\n",[23,4809,4810],{"__ignoreMap":62},[66,4811,4812,4814],{"class":68,"line":69},[66,4813,106],{"class":72},[66,4815,4816],{"class":113}," count_;\n",[15,4818,4819],{},"就可能出现：",[57,4821,4824],{"className":4822,"code":4823,"language":307,"meta":62},[305],"线程1：++count_\n\n线程2：++count_\n",[23,4825,4823],{"__ignoreMap":62},[15,4827,4828],{},"同时执行，从而产生数据竞争。",[15,4830,4831],{},"Boost.Asio 提供的：",[57,4833,4835],{"className":59,"code":4834,"language":61,"meta":62,"style":62},"strand\n",[23,4836,4837],{"__ignoreMap":62},[66,4838,4839],{"class":68,"line":69},[66,4840,4834],{"class":113},[15,4842,4843,4844,4847],{},"就是用来解决这种 ",[295,4845,4846],{},"handler 并发执行"," 问题的。",[15,4849,4850],{},"可以先记住最核心的一句话：",[12,4852,4853],{},[15,4854,4855],{},[295,4856,4857,4858,4860],{},"绑定到同一个 ",[23,4859,4738],{}," 的 handler，不会彼此并发执行。",[15,4862,4863],{},"也就是说，即使：",[57,4865,4868],{"className":4866,"code":4867,"language":307,"meta":62},[305],"多个线程同时运行 io_context\n",[23,4869,4867],{"__ignoreMap":62},[15,4871,4872],{},"同一个 strand 中的 handler 仍然只能：",[57,4874,4877],{"className":4875,"code":4876,"language":307,"meta":62},[305],"一个执行完\n↓\n另一个再执行\n",[23,4878,4876],{"__ignoreMap":62},[35,4880],{},[47,4882,55],{"id":4883},"完整代码-7",[57,4885,4887],{"className":59,"code":4886,"language":61,"meta":62,"style":62},"#include \u003Cboost\u002Fasio.hpp>\n#include \u003Cboost\u002Fsystem\u002Ferror_code.hpp>\n#include \u003Cchrono>\n#include \u003Cfunctional>\n#include \u003Cprint>\n#include \u003Cthread>\n\nclass StrandCounter\n{\npublic:\n    explicit StrandCounter(boost::asio::io_context& io)\n        : strand_(boost::asio::make_strand(io)),\n          timer1_(io, std::chrono::seconds(1)),\n          timer2_(io, std::chrono::seconds(1)),\n          count_(0)\n    {\n        \u002F\u002F timer1 到期后执行的 handler，\n        \u002F\u002F 通过 bind_executor() 绑定到 strand_。\n        timer1_.async_wait(\n            boost::asio::bind_executor(\n                strand_,\n                std::bind(\n                    &StrandCounter::on_timer,\n                    this,\n                    std::placeholders::_1,\n                    1)));\n\n        \u002F\u002F timer2 的 handler 也绑定到同一个 strand_。\n        timer2_.async_wait(\n            boost::asio::bind_executor(\n                strand_,\n                std::bind(\n                    &StrandCounter::on_timer,\n                    this,\n                    std::placeholders::_1,\n                    2)));\n    }\n\nprivate:\n    void on_timer(\n        const boost::system::error_code& ec,\n        int id)\n    {\n        if (ec)\n        {\n            std::println(\n                \"timer{} 取消：{}\",\n                id,\n                ec.message());\n\n            return;\n        }\n\n        ++count_;\n\n        std::println(\n            \"timer{} 回调执行，count = {}，线程 id = {}\",\n            id,\n            count_,\n            std::this_thread::get_id());\n    }\n\nprivate:\n    boost::asio::strand\u003C\n        boost::asio::io_context::executor_type>\n        strand_;\n\n    boost::asio::steady_timer timer1_;\n    boost::asio::steady_timer timer2_;\n\n    int count_;\n};\n\nvoid run_io(\n    boost::asio::io_context* io,\n    const std::string& name)\n{\n    std::println(\n        \"{} 开始 run，线程 id = {}\",\n        name,\n        std::this_thread::get_id());\n\n    io->run();\n\n    std::println(\"{} run 返回\", name);\n}\n\nint main()\n{\n    boost::asio::io_context io;\n\n    StrandCounter counter(io);\n\n    std::thread t1(\n        std::bind(\n            run_io,\n            &io,\n            std::string(\"线程1\")));\n\n    std::thread t2(\n        std::bind(\n            run_io,\n            &io,\n            std::string(\"线程2\")));\n\n    t1.join();\n    t2.join();\n\n    std::println(\"main：结束\");\n\n    return 0;\n}\n",[23,4888,4889,4895,4901,4907,4913,4919,4925,4929,4936,4940,4944,4969,4992,5015,5037,5049,5053,5058,5063,5072,5088,5093,5104,5114,5121,5132,5139,5143,5148,5156,5170,5174,5184,5192,5198,5208,5215,5219,5223,5227,5235,5256,5266,5270,5276,5280,5290,5297,5302,5311,5315,5321,5325,5329,5337,5341,5351,5358,5363,5368,5382,5386,5390,5394,5408,5427,5432,5436,5446,5456,5461,5468,5473,5478,5487,5506,5524,5529,5540,5548,5554,5569,5574,5583,5588,5604,5609,5614,5623,5628,5639,5644,5655,5660,5671,5682,5688,5697,5712,5717,5728,5739,5744,5751,5766,5771,5780,5789,5794,5810,5815,5824],{"__ignoreMap":62},[66,4890,4891,4893],{"class":68,"line":69},[66,4892,73],{"class":72},[66,4894,77],{"class":76},[66,4896,4897,4899],{"class":68,"line":80},[66,4898,73],{"class":72},[66,4900,515],{"class":76},[66,4902,4903,4905],{"class":68,"line":88},[66,4904,73],{"class":72},[66,4906,85],{"class":76},[66,4908,4909,4911],{"class":68,"line":96},[66,4910,73],{"class":72},[66,4912,528],{"class":76},[66,4914,4915,4917],{"class":68,"line":103},[66,4916,73],{"class":72},[66,4918,93],{"class":76},[66,4920,4921,4923],{"class":68,"line":117},[66,4922,73],{"class":72},[66,4924,4025],{"class":76},[66,4926,4927],{"class":68,"line":123},[66,4928,100],{"emptyLinePlaceholder":99},[66,4930,4931,4933],{"class":68,"line":130},[66,4932,2577],{"class":72},[66,4934,4935],{"class":109}," StrandCounter\n",[66,4937,4938],{"class":68,"line":136},[66,4939,120],{"class":113},[66,4941,4942],{"class":68,"line":151},[66,4943,2589],{"class":72},[66,4945,4946,4948,4951,4953,4955,4957,4959,4961,4963,4965,4967],{"class":68,"line":156},[66,4947,2594],{"class":72},[66,4949,4950],{"class":109}," StrandCounter",[66,4952,193],{"class":113},[66,4954,2602],{"class":109},[66,4956,142],{"class":113},[66,4958,145],{"class":109},[66,4960,142],{"class":113},[66,4962,404],{"class":109},[66,4964,566],{"class":72},[66,4966,2615],{"class":569},[66,4968,429],{"class":113},[66,4970,4971,4973,4976,4978,4980,4982,4984,4986,4989],{"class":68,"line":162},[66,4972,2622],{"class":113},[66,4974,4975],{"class":109},"strand_",[66,4977,193],{"class":113},[66,4979,2602],{"class":109},[66,4981,142],{"class":113},[66,4983,145],{"class":109},[66,4985,142],{"class":113},[66,4987,4988],{"class":109},"make_strand",[66,4990,4991],{"class":113},"(io)),\n",[66,4993,4994,4997,4999,5001,5003,5005,5007,5009,5011,5013],{"class":68,"line":203},[66,4995,4996],{"class":109},"          timer1_",[66,4998,177],{"class":113},[66,5000,180],{"class":109},[66,5002,142],{"class":113},[66,5004,185],{"class":109},[66,5006,142],{"class":113},[66,5008,190],{"class":109},[66,5010,193],{"class":113},[66,5012,1363],{"class":196},[66,5014,3382],{"class":113},[66,5016,5017,5019,5021,5023,5025,5027,5029,5031,5033,5035],{"class":68,"line":208},[66,5018,3387],{"class":109},[66,5020,177],{"class":113},[66,5022,180],{"class":109},[66,5024,142],{"class":113},[66,5026,185],{"class":109},[66,5028,142],{"class":113},[66,5030,190],{"class":109},[66,5032,193],{"class":113},[66,5034,1363],{"class":196},[66,5036,3382],{"class":113},[66,5038,5039,5042,5044,5047],{"class":68,"line":227},[66,5040,5041],{"class":109},"          count_",[66,5043,193],{"class":113},[66,5045,5046],{"class":196},"0",[66,5048,429],{"class":113},[66,5050,5051],{"class":68,"line":232},[66,5052,589],{"class":113},[66,5054,5055],{"class":68,"line":238},[66,5056,5057],{"class":126},"        \u002F\u002F timer1 到期后执行的 handler，\n",[66,5059,5060],{"class":68,"line":250},[66,5061,5062],{"class":126},"        \u002F\u002F 通过 bind_executor() 绑定到 strand_。\n",[66,5064,5065,5067,5069],{"class":68,"line":255},[66,5066,3437],{"class":113},[66,5068,762],{"class":109},[66,5070,5071],{"class":113},"(\n",[66,5073,5074,5077,5079,5081,5083,5086],{"class":68,"line":271},[66,5075,5076],{"class":109},"            boost",[66,5078,142],{"class":113},[66,5080,145],{"class":109},[66,5082,142],{"class":113},[66,5084,5085],{"class":109},"bind_executor",[66,5087,5071],{"class":113},[66,5089,5090],{"class":68,"line":276},[66,5091,5092],{"class":113},"                strand_,\n",[66,5094,5095,5098,5100,5102],{"class":68,"line":288},[66,5096,5097],{"class":109},"                std",[66,5099,142],{"class":113},[66,5101,771],{"class":109},[66,5103,5071],{"class":113},[66,5105,5106,5109,5112],{"class":68,"line":684},[66,5107,5108],{"class":72},"                    &",[66,5110,5111],{"class":109},"StrandCounter",[66,5113,2696],{"class":113},[66,5115,5116,5119],{"class":68,"line":689},[66,5117,5118],{"class":196},"                    this",[66,5120,1849],{"class":113},[66,5122,5123,5126,5128,5130],{"class":68,"line":694},[66,5124,5125],{"class":109},"                    std",[66,5127,142],{"class":113},[66,5129,781],{"class":109},[66,5131,1449],{"class":113},[66,5133,5134,5137],{"class":68,"line":725},[66,5135,5136],{"class":196},"                    1",[66,5138,1465],{"class":113},[66,5140,5141],{"class":68,"line":730},[66,5142,100],{"emptyLinePlaceholder":99},[66,5144,5145],{"class":68,"line":746},[66,5146,5147],{"class":126},"        \u002F\u002F timer2 的 handler 也绑定到同一个 strand_。\n",[66,5149,5150,5152,5154],{"class":68,"line":751},[66,5151,3484],{"class":113},[66,5153,762],{"class":109},[66,5155,5071],{"class":113},[66,5157,5158,5160,5162,5164,5166,5168],{"class":68,"line":757},[66,5159,5076],{"class":109},[66,5161,142],{"class":113},[66,5163,145],{"class":109},[66,5165,142],{"class":113},[66,5167,5085],{"class":109},[66,5169,5071],{"class":113},[66,5171,5172],{"class":68,"line":787},[66,5173,5092],{"class":113},[66,5175,5176,5178,5180,5182],{"class":68,"line":792},[66,5177,5097],{"class":109},[66,5179,142],{"class":113},[66,5181,771],{"class":109},[66,5183,5071],{"class":113},[66,5185,5186,5188,5190],{"class":68,"line":808},[66,5187,5108],{"class":72},[66,5189,5111],{"class":109},[66,5191,2696],{"class":113},[66,5193,5194,5196],{"class":68,"line":824},[66,5195,5118],{"class":196},[66,5197,1849],{"class":113},[66,5199,5200,5202,5204,5206],{"class":68,"line":829},[66,5201,5125],{"class":109},[66,5203,142],{"class":113},[66,5205,781],{"class":109},[66,5207,1449],{"class":113},[66,5209,5210,5213],{"class":68,"line":840},[66,5211,5212],{"class":196},"                    2",[66,5214,1465],{"class":113},[66,5216,5217],{"class":68,"line":845},[66,5218,624],{"class":113},[66,5220,5221],{"class":68,"line":861},[66,5222,100],{"emptyLinePlaceholder":99},[66,5224,5225],{"class":68,"line":866},[66,5226,2726],{"class":72},[66,5228,5229,5231,5233],{"class":68,"line":875},[66,5230,2731],{"class":72},[66,5232,545],{"class":109},[66,5234,5071],{"class":113},[66,5236,5237,5240,5242,5244,5246,5248,5250,5252,5254],{"class":68,"line":1548},[66,5238,5239],{"class":72},"        const",[66,5241,553],{"class":109},[66,5243,142],{"class":113},[66,5245,558],{"class":109},[66,5247,142],{"class":113},[66,5249,563],{"class":109},[66,5251,566],{"class":72},[66,5253,570],{"class":569},[66,5255,1849],{"class":113},[66,5257,5258,5261,5264],{"class":68,"line":1553},[66,5259,5260],{"class":72},"        int",[66,5262,5263],{"class":569}," id",[66,5265,429],{"class":113},[66,5267,5268],{"class":68,"line":1576},[66,5269,589],{"class":113},[66,5271,5272,5274],{"class":68,"line":1581},[66,5273,2762],{"class":72},[66,5275,584],{"class":113},[66,5277,5278],{"class":68,"line":1598},[66,5279,2769],{"class":113},[66,5281,5282,5284,5286,5288],{"class":68,"line":1603},[66,5283,2774],{"class":109},[66,5285,142],{"class":113},[66,5287,216],{"class":109},[66,5289,5071],{"class":113},[66,5291,5292,5295],{"class":68,"line":1612},[66,5293,5294],{"class":76},"                \"timer{} 取消：{}\"",[66,5296,1849],{"class":113},[66,5298,5299],{"class":68,"line":2219},[66,5300,5301],{"class":113},"                id,\n",[66,5303,5304,5307,5309],{"class":68,"line":2231},[66,5305,5306],{"class":113},"                ec.",[66,5308,609],{"class":109},[66,5310,612],{"class":113},[66,5312,5313],{"class":68,"line":2240},[66,5314,100],{"emptyLinePlaceholder":99},[66,5316,5317,5319],{"class":68,"line":2248},[66,5318,2794],{"class":72},[66,5320,285],{"class":113},[66,5322,5323],{"class":68,"line":2253},[66,5324,2801],{"class":113},[66,5326,5327],{"class":68,"line":2262},[66,5328,100],{"emptyLinePlaceholder":99},[66,5330,5331,5334],{"class":68,"line":2267},[66,5332,5333],{"class":72},"        ++",[66,5335,5336],{"class":113},"count_;\n",[66,5338,5339],{"class":68,"line":2282},[66,5340,100],{"emptyLinePlaceholder":99},[66,5342,5343,5345,5347,5349],{"class":68,"line":2287},[66,5344,594],{"class":109},[66,5346,142],{"class":113},[66,5348,216],{"class":109},[66,5350,5071],{"class":113},[66,5352,5353,5356],{"class":68,"line":2296},[66,5354,5355],{"class":76},"            \"timer{} 回调执行，count = {}，线程 id = {}\"",[66,5357,1849],{"class":113},[66,5359,5360],{"class":68,"line":3782},[66,5361,5362],{"class":113},"            id,\n",[66,5364,5365],{"class":68,"line":3787},[66,5366,5367],{"class":113},"            count_,\n",[66,5369,5370,5372,5374,5376,5378,5380],{"class":68,"line":3798},[66,5371,2774],{"class":109},[66,5373,142],{"class":113},[66,5375,4140],{"class":109},[66,5377,142],{"class":113},[66,5379,4145],{"class":109},[66,5381,612],{"class":113},[66,5383,5384],{"class":68,"line":3809},[66,5385,624],{"class":113},[66,5387,5388],{"class":68,"line":3814},[66,5389,100],{"emptyLinePlaceholder":99},[66,5391,5392],{"class":68,"line":3829},[66,5393,2726],{"class":72},[66,5395,5396,5398,5400,5402,5405],{"class":68,"line":3834},[66,5397,139],{"class":109},[66,5399,142],{"class":113},[66,5401,145],{"class":109},[66,5403,5404],{"class":113},"::strand",[66,5406,5407],{"class":72},"\u003C\n",[66,5409,5410,5413,5415,5417,5419,5421,5424],{"class":68,"line":3843},[66,5411,5412],{"class":109},"        boost",[66,5414,142],{"class":113},[66,5416,145],{"class":109},[66,5418,142],{"class":113},[66,5420,404],{"class":109},[66,5422,5423],{"class":113},"::executor_type",[66,5425,5426],{"class":72},">\n",[66,5428,5429],{"class":68,"line":3848},[66,5430,5431],{"class":113},"        strand_;\n",[66,5433,5434],{"class":68,"line":3864},[66,5435,100],{"emptyLinePlaceholder":99},[66,5437,5438,5440,5442,5444],{"class":68,"line":3869},[66,5439,139],{"class":109},[66,5441,142],{"class":113},[66,5443,145],{"class":109},[66,5445,3744],{"class":113},[66,5447,5448,5450,5452,5454],{"class":68,"line":3878},[66,5449,139],{"class":109},[66,5451,142],{"class":113},[66,5453,145],{"class":109},[66,5455,3755],{"class":113},[66,5457,5459],{"class":68,"line":5458},70,[66,5460,100],{"emptyLinePlaceholder":99},[66,5462,5464,5466],{"class":68,"line":5463},71,[66,5465,2165],{"class":72},[66,5467,4816],{"class":113},[66,5469,5471],{"class":68,"line":5470},72,[66,5472,2852],{"class":113},[66,5474,5476],{"class":68,"line":5475},73,[66,5477,100],{"emptyLinePlaceholder":99},[66,5479,5481,5483,5485],{"class":68,"line":5480},74,[66,5482,447],{"class":72},[66,5484,4162],{"class":109},[66,5486,5071],{"class":113},[66,5488,5490,5492,5494,5496,5498,5500,5502,5504],{"class":68,"line":5489},75,[66,5491,139],{"class":109},[66,5493,142],{"class":113},[66,5495,145],{"class":109},[66,5497,142],{"class":113},[66,5499,404],{"class":109},[66,5501,1866],{"class":72},[66,5503,2615],{"class":569},[66,5505,1849],{"class":113},[66,5507,5509,5512,5514,5516,5518,5520,5522],{"class":68,"line":5508},76,[66,5510,5511],{"class":72},"    const",[66,5513,1212],{"class":109},[66,5515,142],{"class":113},[66,5517,1217],{"class":109},[66,5519,566],{"class":72},[66,5521,1222],{"class":569},[66,5523,429],{"class":113},[66,5525,5527],{"class":68,"line":5526},77,[66,5528,120],{"class":113},[66,5530,5532,5534,5536,5538],{"class":68,"line":5531},78,[66,5533,211],{"class":109},[66,5535,142],{"class":113},[66,5537,216],{"class":109},[66,5539,5071],{"class":113},[66,5541,5543,5546],{"class":68,"line":5542},79,[66,5544,5545],{"class":76},"        \"{} 开始 run，线程 id = {}\"",[66,5547,1849],{"class":113},[66,5549,5551],{"class":68,"line":5550},80,[66,5552,5553],{"class":113},"        name,\n",[66,5555,5557,5559,5561,5563,5565,5567],{"class":68,"line":5556},81,[66,5558,594],{"class":109},[66,5560,142],{"class":113},[66,5562,4140],{"class":109},[66,5564,142],{"class":113},[66,5566,4145],{"class":109},[66,5568,612],{"class":113},[66,5570,5572],{"class":68,"line":5571},82,[66,5573,100],{"emptyLinePlaceholder":99},[66,5575,5577,5579,5581],{"class":68,"line":5576},83,[66,5578,4236],{"class":113},[66,5580,835],{"class":109},[66,5582,247],{"class":113},[66,5584,5586],{"class":68,"line":5585},84,[66,5587,100],{"emptyLinePlaceholder":99},[66,5589,5591,5593,5595,5597,5599,5602],{"class":68,"line":5590},85,[66,5592,211],{"class":109},[66,5594,142],{"class":113},[66,5596,216],{"class":109},[66,5598,193],{"class":113},[66,5600,5601],{"class":76},"\"{} run 返回\"",[66,5603,1288],{"class":113},[66,5605,5607],{"class":68,"line":5606},86,[66,5608,291],{"class":113},[66,5610,5612],{"class":68,"line":5611},87,[66,5613,100],{"emptyLinePlaceholder":99},[66,5615,5617,5619,5621],{"class":68,"line":5616},88,[66,5618,106],{"class":72},[66,5620,110],{"class":109},[66,5622,114],{"class":113},[66,5624,5626],{"class":68,"line":5625},89,[66,5627,120],{"class":113},[66,5629,5631,5633,5635,5637],{"class":68,"line":5630},90,[66,5632,139],{"class":109},[66,5634,142],{"class":113},[66,5636,145],{"class":109},[66,5638,148],{"class":113},[66,5640,5642],{"class":68,"line":5641},91,[66,5643,100],{"emptyLinePlaceholder":99},[66,5645,5647,5650,5653],{"class":68,"line":5646},92,[66,5648,5649],{"class":113},"    StrandCounter ",[66,5651,5652],{"class":109},"counter",[66,5654,2901],{"class":113},[66,5656,5658],{"class":68,"line":5657},93,[66,5659,100],{"emptyLinePlaceholder":99},[66,5661,5663,5665,5667,5669],{"class":68,"line":5662},94,[66,5664,211],{"class":109},[66,5666,4470],{"class":113},[66,5668,4473],{"class":109},[66,5670,5071],{"class":113},[66,5672,5674,5676,5678,5680],{"class":68,"line":5673},95,[66,5675,594],{"class":109},[66,5677,142],{"class":113},[66,5679,771],{"class":109},[66,5681,5071],{"class":113},[66,5683,5685],{"class":68,"line":5684},96,[66,5686,5687],{"class":113},"            run_io,\n",[66,5689,5691,5694],{"class":68,"line":5690},97,[66,5692,5693],{"class":72},"            &",[66,5695,5696],{"class":113},"io,\n",[66,5698,5700,5702,5704,5706,5708,5710],{"class":68,"line":5699},98,[66,5701,2774],{"class":109},[66,5703,142],{"class":113},[66,5705,1217],{"class":109},[66,5707,193],{"class":113},[66,5709,4500],{"class":76},[66,5711,1465],{"class":113},[66,5713,5715],{"class":68,"line":5714},99,[66,5716,100],{"emptyLinePlaceholder":99},[66,5718,5720,5722,5724,5726],{"class":68,"line":5719},100,[66,5721,211],{"class":109},[66,5723,4470],{"class":113},[66,5725,4511],{"class":109},[66,5727,5071],{"class":113},[66,5729,5731,5733,5735,5737],{"class":68,"line":5730},101,[66,5732,594],{"class":109},[66,5734,142],{"class":113},[66,5736,771],{"class":109},[66,5738,5071],{"class":113},[66,5740,5742],{"class":68,"line":5741},102,[66,5743,5687],{"class":113},[66,5745,5747,5749],{"class":68,"line":5746},103,[66,5748,5693],{"class":72},[66,5750,5696],{"class":113},[66,5752,5754,5756,5758,5760,5762,5764],{"class":68,"line":5753},104,[66,5755,2774],{"class":109},[66,5757,142],{"class":113},[66,5759,1217],{"class":109},[66,5761,193],{"class":113},[66,5763,4536],{"class":76},[66,5765,1465],{"class":113},[66,5767,5769],{"class":68,"line":5768},105,[66,5770,100],{"emptyLinePlaceholder":99},[66,5772,5774,5776,5778],{"class":68,"line":5773},106,[66,5775,4547],{"class":113},[66,5777,4550],{"class":109},[66,5779,247],{"class":113},[66,5781,5783,5785,5787],{"class":68,"line":5782},107,[66,5784,4557],{"class":113},[66,5786,4550],{"class":109},[66,5788,247],{"class":113},[66,5790,5792],{"class":68,"line":5791},108,[66,5793,100],{"emptyLinePlaceholder":99},[66,5795,5797,5799,5801,5803,5805,5808],{"class":68,"line":5796},109,[66,5798,211],{"class":109},[66,5800,142],{"class":113},[66,5802,216],{"class":109},[66,5804,193],{"class":113},[66,5806,5807],{"class":76},"\"main：结束\"",[66,5809,224],{"class":113},[66,5811,5813],{"class":68,"line":5812},110,[66,5814,100],{"emptyLinePlaceholder":99},[66,5816,5818,5820,5822],{"class":68,"line":5817},111,[66,5819,279],{"class":72},[66,5821,282],{"class":196},[66,5823,285],{"class":113},[66,5825,5827],{"class":68,"line":5826},112,[66,5828,291],{"class":113},[35,5830],{},[47,5832,5834,5835,5837],{"id":5833},"如果没有-strand-会发生什么","如果没有 ",[23,5836,4738],{}," 会发生什么",[15,5839,5840],{},"假设我们不使用：",[57,5842,5844],{"className":59,"code":5843,"language":61,"meta":62,"style":62},"boost::asio::bind_executor(strand_, handler);\n",[23,5845,5846],{"__ignoreMap":62},[66,5847,5848,5850,5852,5854,5856,5858],{"class":68,"line":69},[66,5849,2602],{"class":109},[66,5851,142],{"class":113},[66,5853,145],{"class":109},[66,5855,142],{"class":113},[66,5857,5085],{"class":109},[66,5859,5860],{"class":113},"(strand_, handler);\n",[15,5862,5863],{},"而是直接：",[57,5865,5867],{"className":59,"code":5866,"language":61,"meta":62,"style":62},"timer1_.async_wait(\n    std::bind(\n        &StrandCounter::on_timer,\n        this,\n        std::placeholders::_1,\n        1));\n\ntimer2_.async_wait(\n    std::bind(\n        &StrandCounter::on_timer,\n        this,\n        std::placeholders::_1,\n        2));\n",[23,5868,5869,5878,5888,5897,5904,5914,5921,5925,5934,5944,5952,5958,5968],{"__ignoreMap":62},[66,5870,5871,5874,5876],{"class":68,"line":69},[66,5872,5873],{"class":113},"timer1_.",[66,5875,762],{"class":109},[66,5877,5071],{"class":113},[66,5879,5880,5882,5884,5886],{"class":68,"line":80},[66,5881,211],{"class":109},[66,5883,142],{"class":113},[66,5885,771],{"class":109},[66,5887,5071],{"class":113},[66,5889,5890,5893,5895],{"class":68,"line":88},[66,5891,5892],{"class":72},"        &",[66,5894,5111],{"class":109},[66,5896,2696],{"class":113},[66,5898,5899,5902],{"class":68,"line":96},[66,5900,5901],{"class":196},"        this",[66,5903,1849],{"class":113},[66,5905,5906,5908,5910,5912],{"class":68,"line":103},[66,5907,594],{"class":109},[66,5909,142],{"class":113},[66,5911,781],{"class":109},[66,5913,1449],{"class":113},[66,5915,5916,5919],{"class":68,"line":117},[66,5917,5918],{"class":196},"        1",[66,5920,200],{"class":113},[66,5922,5923],{"class":68,"line":123},[66,5924,100],{"emptyLinePlaceholder":99},[66,5926,5927,5930,5932],{"class":68,"line":130},[66,5928,5929],{"class":113},"timer2_.",[66,5931,762],{"class":109},[66,5933,5071],{"class":113},[66,5935,5936,5938,5940,5942],{"class":68,"line":136},[66,5937,211],{"class":109},[66,5939,142],{"class":113},[66,5941,771],{"class":109},[66,5943,5071],{"class":113},[66,5945,5946,5948,5950],{"class":68,"line":151},[66,5947,5892],{"class":72},[66,5949,5111],{"class":109},[66,5951,2696],{"class":113},[66,5953,5954,5956],{"class":68,"line":156},[66,5955,5901],{"class":196},[66,5957,1849],{"class":113},[66,5959,5960,5962,5964,5966],{"class":68,"line":162},[66,5961,594],{"class":109},[66,5963,142],{"class":113},[66,5965,781],{"class":109},[66,5967,1449],{"class":113},[66,5969,5970,5973],{"class":68,"line":203},[66,5971,5972],{"class":196},"        2",[66,5974,200],{"class":113},[15,5976,5977],{},"同时有两个线程：",[57,5979,5981],{"className":5980,"code":4785,"language":307,"meta":62},[305],[23,5982,4785],{"__ignoreMap":62},[15,5984,5985],{},"那么当两个 timer 都到期以后，完全可能出现：",[57,5987,5990],{"className":5988,"code":5989,"language":307,"meta":62},[305],"线程1\n↓\n取到 timer1 handler\n↓\n进入 on_timer()\n\n\n线程2\n↓\n取到 timer2 handler\n↓\n同时进入 on_timer()\n",[23,5991,5989],{"__ignoreMap":62},[15,5993,5994],{},"也就是：",[57,5996,5999],{"className":5997,"code":5998,"language":307,"meta":62},[305],"时间 ─────────────────────→\n\n线程1： [ timer1 handler       ]\n\n线程2：    [ timer2 handler       ]\n              ↑\n            发生重叠\n",[23,6000,5998],{"__ignoreMap":62},[15,6002,6003],{},"两个 handler 里面都有：",[57,6005,6007],{"className":59,"code":6006,"language":61,"meta":62,"style":62},"++count_;\n",[23,6008,6009],{"__ignoreMap":62},[66,6010,6011,6014],{"class":68,"line":69},[66,6012,6013],{"class":72},"++",[66,6015,5336],{"class":113},[15,6017,6018],{},"而：",[57,6020,6021],{"className":59,"code":4807,"language":61,"meta":62,"style":62},[23,6022,6023],{"__ignoreMap":62},[66,6024,6025,6027],{"class":68,"line":69},[66,6026,106],{"class":72},[66,6028,4816],{"class":113},[15,6030,6031,6032,448],{},"只是普通 ",[23,6033,106],{},[15,6035,6036],{},"所以两个线程同时修改它就会产生data race。",[35,6038],{},[47,6040,6042,6043,6045],{"id":6041},"加上-strand-后发生什么","加上 ",[23,6044,4738],{}," 后发生什么",[15,6047,6048],{},"我们先创建：",[57,6050,6052],{"className":59,"code":6051,"language":61,"meta":62,"style":62},"strand_(boost::asio::make_strand(io))\n",[23,6053,6054],{"__ignoreMap":62},[66,6055,6056,6058,6060,6062,6064,6066,6068,6070],{"class":68,"line":69},[66,6057,4975],{"class":109},[66,6059,193],{"class":113},[66,6061,2602],{"class":109},[66,6063,142],{"class":113},[66,6065,145],{"class":109},[66,6067,142],{"class":113},[66,6069,4988],{"class":109},[66,6071,6072],{"class":113},"(io))\n",[15,6074,6075],{},"可以先把它理解成：",[12,6077,6078],{},[15,6079,6080],{},[295,6081,6082,6083,6085],{},"在这个 ",[23,6084,404],{}," 上额外建立一条“串行执行通道”。",[15,6087,6088],{},"然后把两个 handler 都绑定到：",[57,6090,6092],{"className":59,"code":6091,"language":61,"meta":62,"style":62},"strand_\n",[23,6093,6094],{"__ignoreMap":62},[66,6095,6096],{"class":68,"line":69},[66,6097,6091],{"class":113},[15,6099,4781],{},[57,6101,6103],{"className":59,"code":6102,"language":61,"meta":62,"style":62},"boost::asio::bind_executor(\n    strand_,\n    handler);\n",[23,6104,6105,6119,6124],{"__ignoreMap":62},[66,6106,6107,6109,6111,6113,6115,6117],{"class":68,"line":69},[66,6108,2602],{"class":109},[66,6110,142],{"class":113},[66,6112,145],{"class":109},[66,6114,142],{"class":113},[66,6116,5085],{"class":109},[66,6118,5071],{"class":113},[66,6120,6121],{"class":68,"line":80},[66,6122,6123],{"class":113},"    strand_,\n",[66,6125,6126],{"class":68,"line":88},[66,6127,6128],{"class":113},"    handler);\n",[15,6130,6131],{},"此时：",[57,6133,6136],{"className":6134,"code":6135,"language":307,"meta":62},[305],"timer1 handler ──┐\n                 ├── 同一个 strand_\ntimer2 handler ──┘\n",[23,6137,6135],{"__ignoreMap":62},[15,6139,6140,6141,6143],{},"于是 ",[23,6142,4738],{}," 会保证：",[57,6145,6148],{"className":6146,"code":6147,"language":307,"meta":62},[305],"timer1 handler\n\n和\n\ntimer2 handler\n",[23,6149,6147],{"__ignoreMap":62},[15,6151,6152],{},"不会同时执行。",[15,6154,6155],{},"可能是：",[57,6157,6160],{"className":6158,"code":6159,"language":307,"meta":62},[305],"线程1：\ntimer1 handler 开始\n↓\n++count_\n↓\ntimer1 handler 结束\n\n线程2：\ntimer2 handler 开始\n↓\n++count_\n↓\ntimer2 handler 结束\n",[23,6161,6159],{"__ignoreMap":62},[15,6163,6164],{},"也可能反过来：",[57,6166,6169],{"className":6167,"code":6168,"language":307,"meta":62},[305],"线程2：\ntimer2 handler\n\n然后\n\n线程1：\ntimer1 handler\n",[23,6170,6168],{"__ignoreMap":62},[15,6172,6173],{},"但不会出现两个 handler 的执行时间发生重叠。",[15,6175,6176],{},"可以画成：",[57,6178,6181],{"className":6179,"code":6180,"language":307,"meta":62},[305],"时间 ─────────────────────────→\n\n线程1： [ timer1 handler ]\n\n线程2：                    [ timer2 handler ]\n",[23,6182,6180],{"__ignoreMap":62},[15,6184,6185],{},"或者：",[57,6187,6190],{"className":6188,"code":6189,"language":307,"meta":62},[305],"时间 ─────────────────────────→\n\n线程2： [ timer2 handler ]\n\n线程1：                    [ timer1 handler ]\n",[23,6191,6189],{"__ignoreMap":62},[15,6193,6194],{},"但不会：",[57,6196,6199],{"className":6197,"code":6198,"language":307,"meta":62},[305],"时间 ─────────────────────────→\n\n线程1： [ timer1 handler       ]\n\n线程2：       [ timer2 handler       ]\n                  ↑\n                同时执行\n",[23,6200,6198],{"__ignoreMap":62},[35,6202],{},[47,6204,6206,6208],{"id":6205},"strand-不是固定线程",[23,6207,4738],{}," 不是“固定线程”",[15,6210,6211,6212,6214],{},"这是理解 ",[23,6213,4738],{}," 最重要的一点之一。",[15,6216,6217,6219],{},[23,6218,4738],{}," 并不是说：",[57,6221,6224],{"className":6222,"code":6223,"language":307,"meta":62},[305],"所有绑定到 strand 的 handler\n永远都在线程1执行\n",[23,6225,6223],{"__ignoreMap":62},[15,6227,6228],{},"例如完全可能：",[57,6230,6233],{"className":6231,"code":6232,"language":307,"meta":62},[305],"timer1 handler\n→ 在线程1执行\n\ntimer2 handler\n→ 在线程2执行\n",[23,6234,6232],{"__ignoreMap":62},[15,6236,6237],{},"只要它们：",[57,6239,6242],{"className":6240,"code":6241,"language":307,"meta":62},[305],"不同时执行\n",[23,6243,6241],{"__ignoreMap":62},[15,6245,6246],{},"就是允许的。",[15,6248,6249],{},"所以：",[57,6251,6254],{"className":6252,"code":6253,"language":307,"meta":62},[305],"strand\n≠ 指定一个固定线程\n",[23,6255,6253],{"__ignoreMap":62},[15,6257,6258],{},"而是：",[57,6260,6263],{"className":6261,"code":6262,"language":307,"meta":62},[305],"strand\n= 保证一组 handler 串行执行\n",[23,6264,6262],{"__ignoreMap":62},[15,6266,6267],{},"换句话说：",[12,6269,6270],{},[15,6271,6272],{},[295,6273,6274],{},"strand 管的是“执行时间不能重叠”，不是“必须在哪个线程上执行”。",[35,6276],{},[47,6278,6280],{"id":6279},"strand-也不是新的线程","strand 也不是新的线程",[15,6282,6283,6285],{},[23,6284,4738],{}," 自己不会：",[57,6287,6290],{"className":6288,"code":6289,"language":307,"meta":62},[305],"创建一个线程\n",[23,6291,6289],{"__ignoreMap":62},[15,6293,6294],{},"它仍然依赖：",[57,6296,6297],{"className":59,"code":899,"language":61,"meta":62,"style":62},[23,6298,6299],{"__ignoreMap":62},[66,6300,6301,6303,6305],{"class":68,"line":69},[66,6302,906],{"class":113},[66,6304,835],{"class":109},[66,6306,247],{"class":113},[15,6308,6309],{},"的那些线程来真正执行 handler。",[15,6311,6312],{},"本例中真正执行 handler 的仍然只有：",[57,6314,6317],{"className":6315,"code":6316,"language":307,"meta":62},[305],"线程1\n\n线程2\n",[23,6318,6316],{"__ignoreMap":62},[15,6320,6321],{},"strand 做的只是：",[57,6323,6326],{"className":6324,"code":6325,"language":307,"meta":62},[305],"控制同一组 handler 的执行关系\n",[23,6327,6325],{"__ignoreMap":62},[15,6329,6330],{},"可以理解成：",[57,6332,6335],{"className":6333,"code":6334,"language":307,"meta":62},[305],"io_context\n        ↓\n ┌──────┴──────┐\n线程1          线程2\n   \\             \u002F\n    \\           \u002F\n      strand\n        ↓\nhandler A\nhandler B\nhandler C\n",[23,6336,6334],{"__ignoreMap":62},[15,6338,6339,6340,6342],{},"handler 仍然由执行 ",[23,6341,484],{}," 的线程来运行，只是 strand 不允许属于自己的两个 handler 同时运行。",[35,6344],{},[47,6346,6348,6349,6352],{"id":6347},"为什么这里的-count_-可以不用-mutex","为什么这里的 ",[23,6350,6351],{},"count_"," 可以不用 mutex",[15,6354,6355],{},"本例中：",[57,6357,6358],{"className":59,"code":6006,"language":61,"meta":62,"style":62},[23,6359,6360],{"__ignoreMap":62},[66,6361,6362,6364],{"class":68,"line":69},[66,6363,6013],{"class":72},[66,6365,5336],{"class":113},[15,6367,6368],{},"只会在：",[57,6370,6372],{"className":59,"code":6371,"language":61,"meta":62,"style":62},"on_timer()\n",[23,6373,6374],{"__ignoreMap":62},[66,6375,6376,6378],{"class":68,"line":69},[66,6377,1017],{"class":109},[66,6379,114],{"class":113},[15,6381,6382],{},"中执行。",[15,6384,6385,6386,6388],{},"而两个 ",[23,6387,3246],{}," 对应的 handler：",[57,6390,6393],{"className":6391,"code":6392,"language":307,"meta":62},[305],"timer1 handler\n\ntimer2 handler\n",[23,6394,6392],{"__ignoreMap":62},[15,6396,6397],{},"都绑定到了同一个：",[57,6399,6400],{"className":59,"code":6091,"language":61,"meta":62,"style":62},[23,6401,6402],{"__ignoreMap":62},[66,6403,6404],{"class":68,"line":69},[66,6405,6091],{"class":113},[15,6407,6408],{},"所以它们不会并发执行。",[15,6410,6411],{},"于是：",[57,6413,6414],{"className":59,"code":6006,"language":61,"meta":62,"style":62},[23,6415,6416],{"__ignoreMap":62},[66,6417,6418,6420],{"class":68,"line":69},[66,6419,6013],{"class":72},[66,6421,5336],{"class":113},[15,6423,6424],{},"也不会被两个线程同时执行。",[15,6426,6427],{},"因此这里不需要再写：",[57,6429,6431],{"className":59,"code":6430,"language":61,"meta":62,"style":62},"std::mutex mutex_;\n\nstd::scoped_lock lock(mutex_);\n++count_;\n",[23,6432,6433,6440,6444,6463],{"__ignoreMap":62},[66,6434,6435,6437],{"class":68,"line":69},[66,6436,180],{"class":109},[66,6438,6439],{"class":113},"::mutex mutex_;\n",[66,6441,6442],{"class":68,"line":80},[66,6443,100],{"emptyLinePlaceholder":99},[66,6445,6446,6448,6450,6453,6456,6458,6461],{"class":68,"line":88},[66,6447,180],{"class":109},[66,6449,142],{"class":113},[66,6451,6452],{"class":109},"scoped_lock",[66,6454,6455],{"class":109}," lock",[66,6457,193],{"class":113},[66,6459,6460],{"class":109},"mutex_",[66,6462,224],{"class":113},[66,6464,6465,6467],{"class":68,"line":96},[66,6466,6013],{"class":72},[66,6468,5336],{"class":113},[15,6470,6471],{},"strand 已经通过：",[57,6473,6476],{"className":6474,"code":6475,"language":307,"meta":62},[305],"串行化 handler\n",[23,6477,6475],{"__ignoreMap":62},[15,6479,6480],{},"避免了这里的并发访问。",[35,6482],{},[47,6484,6486],{"id":6485},"但-strand-不会自动保护整个对象","但 strand 不会自动保护整个对象",[15,6488,6489],{},"这一点也非常重要。",[15,6491,6492],{},"不能因为类里面有：",[57,6494,6495],{"className":59,"code":6091,"language":61,"meta":62,"style":62},[23,6496,6497],{"__ignoreMap":62},[66,6498,6499],{"class":68,"line":69},[66,6500,6091],{"class":113},[15,6502,6503],{},"就认为：",[57,6505,6508],{"className":6506,"code":6507,"language":307,"meta":62},[305],"StrandCounter 整个对象自动线程安全\n",[23,6509,6507],{"__ignoreMap":62},[15,6511,6512],{},"strand 只能保证：",[12,6514,6515],{},[15,6516,6517],{},[295,6518,6519],{},"经过这个 strand 调度的 handler 彼此不并发。",[15,6521,6522],{},"例如本例：",[57,6524,6527],{"className":6525,"code":6526,"language":307,"meta":62},[305],"timer1 handler\n→ strand_\n\ntimer2 handler\n→ strand_\n",[23,6528,6526],{"__ignoreMap":62},[15,6530,6531],{},"所以它们访问：",[57,6533,6535],{"className":59,"code":6534,"language":61,"meta":62,"style":62},"count_\n",[23,6536,6537],{"__ignoreMap":62},[66,6538,6539],{"class":68,"line":69},[66,6540,6534],{"class":113},[15,6542,6543],{},"是安全的。",[15,6545,6546],{},"但如果另外有一个线程直接修改：",[57,6548,6549],{"className":59,"code":5336,"language":61,"meta":62,"style":62},[23,6550,6551],{"__ignoreMap":62},[66,6552,6553],{"class":68,"line":69},[66,6554,5336],{"class":113},[15,6556,6557,6558,6560],{},"或者另一个没有绑定 ",[23,6559,4975],{}," 的 handler 修改：",[57,6562,6563],{"className":59,"code":5336,"language":61,"meta":62,"style":62},[23,6564,6565],{"__ignoreMap":62},[66,6566,6567],{"class":68,"line":69},[66,6568,5336],{"class":113},[15,6570,6571],{},"那么 strand 管不到它。",[15,6573,4781],{},[57,6575,6578],{"className":6576,"code":6577,"language":307,"meta":62},[305],"timer1 handler\n→ strand_\n→ 修改 count_\n\n另一个普通线程\n→ 直接修改 count_\n",[23,6579,6577],{"__ignoreMap":62},[15,6581,6582],{},"这两个还是可能并发。",[15,6584,6585],{},"所以使用 strand 保护某份状态时，需要保证：",[12,6587,6588],{},[15,6589,6590],{},[295,6591,6592],{},"所有可能并发访问这份状态的相关操作，都遵守同一个 strand 的串行化规则。",[35,6594],{},[47,6596,6598,6601],{"id":6597},"bind_executor-是干什么的",[23,6599,6600],{},"bind_executor()"," 是干什么的",[15,6603,3004],{},[57,6605,6606],{"className":59,"code":6102,"language":61,"meta":62,"style":62},[23,6607,6608,6622,6626],{"__ignoreMap":62},[66,6609,6610,6612,6614,6616,6618,6620],{"class":68,"line":69},[66,6611,2602],{"class":109},[66,6613,142],{"class":113},[66,6615,145],{"class":109},[66,6617,142],{"class":113},[66,6619,5085],{"class":109},[66,6621,5071],{"class":113},[66,6623,6624],{"class":68,"line":80},[66,6625,6123],{"class":113},[66,6627,6628],{"class":68,"line":88},[66,6629,6128],{"class":113},[15,6631,6330],{},[12,6633,6634],{},[15,6635,6636],{},[295,6637,6638,6639,448],{},"把这个 handler 的执行器绑定成 ",[23,6640,4975],{},[15,6642,4781],{},[57,6644,6646],{"className":59,"code":6645,"language":61,"meta":62,"style":62},"timer1_.async_wait(\n    boost::asio::bind_executor(\n        strand_,\n        std::bind(\n            &StrandCounter::on_timer,\n            this,\n            std::placeholders::_1,\n            1)));\n",[23,6647,6648,6656,6670,6675,6685,6693,6700,6710],{"__ignoreMap":62},[66,6649,6650,6652,6654],{"class":68,"line":69},[66,6651,5873],{"class":113},[66,6653,762],{"class":109},[66,6655,5071],{"class":113},[66,6657,6658,6660,6662,6664,6666,6668],{"class":68,"line":80},[66,6659,139],{"class":109},[66,6661,142],{"class":113},[66,6663,145],{"class":109},[66,6665,142],{"class":113},[66,6667,5085],{"class":109},[66,6669,5071],{"class":113},[66,6671,6672],{"class":68,"line":88},[66,6673,6674],{"class":113},"        strand_,\n",[66,6676,6677,6679,6681,6683],{"class":68,"line":96},[66,6678,594],{"class":109},[66,6680,142],{"class":113},[66,6682,771],{"class":109},[66,6684,5071],{"class":113},[66,6686,6687,6689,6691],{"class":68,"line":103},[66,6688,5693],{"class":72},[66,6690,5111],{"class":109},[66,6692,2696],{"class":113},[66,6694,6695,6698],{"class":68,"line":117},[66,6696,6697],{"class":196},"            this",[66,6699,1849],{"class":113},[66,6701,6702,6704,6706,6708],{"class":68,"line":123},[66,6703,2774],{"class":109},[66,6705,142],{"class":113},[66,6707,781],{"class":109},[66,6709,1449],{"class":113},[66,6711,6712,6715],{"class":68,"line":130},[66,6713,6714],{"class":196},"            1",[66,6716,1465],{"class":113},[15,6718,6719],{},"原本可以理解成：",[57,6721,6724],{"className":6722,"code":6723,"language":307,"meta":62},[305],"timer1 到期\n↓\nhandler 交给 io_context\n↓\n某个正在 run() 的线程执行\n",[23,6725,6723],{"__ignoreMap":62},[15,6727,6728],{},"加入 strand 后变成：",[57,6730,6733],{"className":6731,"code":6732,"language":307,"meta":62},[305],"timer1 到期\n↓\nhandler 要经过 strand_\n↓\nstrand_ 保证它不会和\n同一个 strand 中的其他 handler 并发\n↓\n再由某个正在 run() 的线程执行\n",[23,6734,6732],{"__ignoreMap":62},[15,6736,6249],{},[57,6738,6740],{"className":59,"code":6739,"language":61,"meta":62,"style":62},"bind_executor(strand_, handler)\n",[23,6741,6742],{"__ignoreMap":62},[66,6743,6744,6746],{"class":68,"line":69},[66,6745,5085],{"class":109},[66,6747,6748],{"class":113},"(strand_, handler)\n",[15,6750,6751],{},"最直观的理解就是：",[12,6753,6754],{},[15,6755,6756],{},[295,6757,6758,6759,6761],{},"让这个 handler 遵守 ",[23,6760,4975],{}," 的串行执行规则。",[35,6763],{},[47,6765,301],{"id":6766},"运行输出与时间顺序-7",[15,6768,6769],{},"程序启动以后：",[57,6771,6774],{"className":6772,"code":6773,"language":307,"meta":62},[305],"线程1 开始 run，线程 id = 140000000000001\n线程2 开始 run，线程 id = 140000000000002\n",[23,6775,6773],{"__ignoreMap":62},[15,6777,6778],{},"两个线程此时都在：",[57,6780,6782],{"className":59,"code":6781,"language":61,"meta":62,"style":62},"io->run();\n",[23,6783,6784],{"__ignoreMap":62},[66,6785,6786,6789,6791],{"class":68,"line":69},[66,6787,6788],{"class":113},"io->",[66,6790,835],{"class":109},[66,6792,247],{"class":113},[15,6794,6795],{},"中等待和执行 Asio 的事件。",[15,6797,2316],{},[57,6799,6802],{"className":6800,"code":6801,"language":307,"meta":62},[305],"timer1\n\ntimer2\n",[23,6803,6801],{"__ignoreMap":62},[15,6805,6806],{},"都到期。",[15,6808,6809],{},"可能输出：",[57,6811,6814],{"className":6812,"code":6813,"language":307,"meta":62},[305],"timer1 回调执行，count = 1，线程 id = 140000000000001\ntimer2 回调执行，count = 2，线程 id = 140000000000002\n\n线程1 run 返回\n线程2 run 返回\n\nmain：结束\n",[23,6815,6813],{"__ignoreMap":62},[15,6817,6818],{},"也可能：",[57,6820,6823],{"className":6821,"code":6822,"language":307,"meta":62},[305],"timer2 回调执行，count = 1，线程 id = 140000000000002\ntimer1 回调执行，count = 2，线程 id = 140000000000001\n",[23,6824,6822],{"__ignoreMap":62},[15,6826,6827],{},"这些都正常。",[15,6829,6830],{},"因为 strand 不保证：",[57,6832,6835],{"className":6833,"code":6834,"language":307,"meta":62},[305],"timer1 一定先执行\n",[23,6836,6834],{"__ignoreMap":62},[15,6838,6839],{},"也不保证：",[57,6841,6844],{"className":6842,"code":6843,"language":307,"meta":62},[305],"timer1 一定在线程1\ntimer2 一定在线程2\n",[23,6845,6843],{"__ignoreMap":62},[15,6847,6848],{},"strand 真正保证的是：",[12,6850,6851],{},[15,6852,6853],{},[295,6854,6855],{},"两个绑定到同一个 strand 的 handler 不会同时执行。",[35,6857],{},[47,6859,6861,1667,6863,6866],{"id":6860},"strand-和-mutex-的思路有什么不同",[23,6862,4738],{},[23,6864,6865],{},"mutex"," 的思路有什么不同",[15,6868,6869],{},"如果不用 strand，也可以自己：",[57,6871,6873],{"className":59,"code":6872,"language":61,"meta":62,"style":62},"std::mutex mutex_;\n",[23,6874,6875],{"__ignoreMap":62},[66,6876,6877,6879],{"class":68,"line":69},[66,6878,180],{"class":109},[66,6880,6439],{"class":113},[15,6882,6883],{},"然后：",[57,6885,6887],{"className":59,"code":6886,"language":61,"meta":62,"style":62},"void on_timer(...)\n{\n    std::scoped_lock lock(mutex_);\n\n    ++count_;\n}\n",[23,6888,6889,6898,6902,6915,6919,6925],{"__ignoreMap":62},[66,6890,6891,6893,6895],{"class":68,"line":69},[66,6892,447],{"class":72},[66,6894,545],{"class":109},[66,6896,6897],{"class":113},"(...)\n",[66,6899,6900],{"class":68,"line":80},[66,6901,120],{"class":113},[66,6903,6904,6906,6909,6912],{"class":68,"line":88},[66,6905,211],{"class":109},[66,6907,6908],{"class":113},"::scoped_lock ",[66,6910,6911],{"class":109},"lock",[66,6913,6914],{"class":113},"(mutex_);\n",[66,6916,6917],{"class":68,"line":96},[66,6918,100],{"emptyLinePlaceholder":99},[66,6920,6921,6923],{"class":68,"line":103},[66,6922,1933],{"class":72},[66,6924,5336],{"class":113},[66,6926,6927],{"class":68,"line":117},[66,6928,291],{"class":113},[15,6930,6931],{},"也可以避免数据竞争。",[15,6933,6934],{},"两种思路分别是：",[57,6936,6939],{"className":6937,"code":6938,"language":307,"meta":62},[305],"mutex\n\n→ handler 可以同时开始执行\n\n→ 但访问共享状态时竞争锁\n",[23,6940,6938],{"__ignoreMap":62},[15,6942,6018],{},[57,6944,6947],{"className":6945,"code":6946,"language":307,"meta":62},[305],"strand\n\n→ 从 handler 调度层面就不让它们并发执行\n",[23,6948,6946],{"__ignoreMap":62},[15,6950,6951],{},"所以在 Boost.Asio 中，如果一组异步 handler：",[57,6953,6956],{"className":6954,"code":6955,"language":307,"meta":62},[305],"本来就应该按串行方式处理同一个对象状态\n",[23,6957,6955],{"__ignoreMap":62},[15,6959,6960],{},"strand 往往是一种很自然的设计。",[15,6962,4781],{},[57,6964,6967],{"className":6965,"code":6966,"language":307,"meta":62},[305],"串口读回调\n\n串口写完成回调\n\n定时器回调\n\n连接状态回调\n",[23,6968,6966],{"__ignoreMap":62},[15,6970,6971],{},"如果它们都操作同一个连接对象的内部状态，就可以让这些 handler 统一经过同一个 strand。",[15,6973,6974],{},[295,6975,6976],{},"总结：",[15,6978,6979],{},"所以 mutex 很适合：一个大函数里面，只有很小一块共享数据需要保护。",[15,6981,6982],{},"而 strand 更适合：一个对象的一系列异步事件，本来就应该一个一个处理。",[35,6984],{},[47,6986,6987],{"id":6987},"本示例最重要的结论",[15,6989,6990,6991,6993],{},"如果一个 ",[23,6992,404],{}," 只有一个线程调用：",[57,6995,6996],{"className":59,"code":899,"language":61,"meta":62,"style":62},[23,6997,6998],{"__ignoreMap":62},[66,6999,7000,7002,7004],{"class":68,"line":69},[66,7001,906],{"class":113},[66,7003,835],{"class":109},[66,7005,247],{"class":113},[15,7007,7008],{},"那么 handler 本身不会并发执行。",[15,7010,7011],{},"但如果：",[57,7013,7016],{"className":7014,"code":7015,"language":307,"meta":62},[305],"多个线程\n↓\n同时 io.run()\n",[23,7017,7015],{"__ignoreMap":62},[15,7019,7020],{},"那么不同 handler 就可能：",[57,7022,7025],{"className":7023,"code":7024,"language":307,"meta":62},[305],"在不同线程上同时执行\n",[23,7026,7024],{"__ignoreMap":62},[15,7028,7029],{},"这时：",[57,7031,7032],{"className":59,"code":4834,"language":61,"meta":62,"style":62},[23,7033,7034],{"__ignoreMap":62},[66,7035,7036],{"class":68,"line":69},[66,7037,4834],{"class":113},[15,7039,7040],{},"可以把某一组 handler 串行化。",[15,7042,7043],{},"最终可以记成：",[57,7045,7048],{"className":7046,"code":7047,"language":307,"meta":62},[305],"多个线程 run(io_context)\n\n        ↓\n\n没有 strand\n\n不同 handler\n可能同时执行\n        ↓\n访问共享状态时\n可能产生 data race\n",[23,7049,7047],{"__ignoreMap":62},[15,7051,7052],{},"使用同一个 strand：",[57,7054,7057],{"className":7055,"code":7056,"language":307,"meta":62},[305],"多个线程 run(io_context)\n\n        ↓\n\nhandler 可以由不同线程执行\n\n        ↓\n\n但是同一个 strand 中的 handler\n不会并发执行\n\n        ↓\n\n相关状态访问被串行化\n",[23,7058,7056],{"__ignoreMap":62},[15,7060,7061],{},"所以一句话记住：",[12,7063,7064],{},[15,7065,7066],{},[295,7067,7068,7070],{},[23,7069,4738],{}," 是 Boost.Asio 提供的 handler 串行化机制：它不固定线程，也不创建线程，只保证绑定到同一个 strand 的 handler 不会彼此并发执行。",[38,7072,7073],{"id":7073},"本节总结",[15,7075,7076],{},"你现在应该记住：",[468,7078,7079,7084,7090,7095,7102,7108,7114],{},[471,7080,7081,7083],{},[23,7082,336],{}," 是同步阻塞。",[471,7085,7086,7089],{},[23,7087,7088],{},"timer.async_wait()"," 是注册异步任务，不阻塞。",[471,7091,7092,7094],{},[23,7093,484],{}," 才是事件循环的入口。",[471,7096,7097,7098,7101],{},"一个线程 ",[23,7099,7100],{},"run()","，回调就在这个线程里顺序执行。",[471,7103,7104,7105,7107],{},"多个线程 ",[23,7106,7100],{},"，回调可能被不同线程执行。",[471,7109,7110,7111,7113],{},"多线程共享数据时，用 ",[23,7112,4738],{}," 避免回调并发。",[471,7115,7116],{},"类里绑定成员函数的标准写法是：",[57,7118,7120],{"className":59,"code":7119,"language":61,"meta":62,"style":62},"std::bind(&ClassName::member_function,\n          this,\n          std::placeholders::_1,\n          std::placeholders::_2)\n",[23,7121,7122,7140,7147,7158],{"__ignoreMap":62},[66,7123,7124,7126,7128,7130,7132,7134,7137],{"class":68,"line":69},[66,7125,180],{"class":109},[66,7127,142],{"class":113},[66,7129,771],{"class":109},[66,7131,193],{"class":113},[66,7133,566],{"class":72},[66,7135,7136],{"class":109},"ClassName",[66,7138,7139],{"class":113},"::member_function,\n",[66,7141,7142,7145],{"class":68,"line":80},[66,7143,7144],{"class":196},"          this",[66,7146,1849],{"class":113},[66,7148,7149,7152,7154,7156],{"class":68,"line":88},[66,7150,7151],{"class":109},"          std",[66,7153,142],{"class":113},[66,7155,781],{"class":109},[66,7157,1449],{"class":113},[66,7159,7160,7162,7164,7166],{"class":68,"line":96},[66,7161,7151],{"class":109},[66,7163,142],{"class":113},[66,7165,781],{"class":109},[66,7167,7168],{"class":113},"::_2)\n",[7170,7171,7172],"style",{},"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 .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 pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}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 .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":62,"searchDepth":80,"depth":80,"links":7174},[7175,7183,7193,7202,7210,7218,7224,7233,7254],{"id":40,"depth":80,"text":7176,"children":7177},"示例 1：普通 main() 里写同步定时器",[7178,7179,7180,7181,7182],{"id":49,"depth":88,"text":49},{"id":55,"depth":88,"text":55},{"id":301,"depth":88,"text":301},{"id":330,"depth":88,"text":330},{"id":360,"depth":88,"text":360},{"id":456,"depth":80,"text":7184,"children":7185},"示例 2：普通 main() 里写异步定时器",[7186,7187,7188,7189,7190,7192],{"id":463,"depth":88,"text":49},{"id":497,"depth":88,"text":55},{"id":884,"depth":88,"text":301},{"id":930,"depth":88,"text":330},{"id":968,"depth":88,"text":7191},"std::bind 说明",{"id":1052,"depth":88,"text":360},{"id":1096,"depth":80,"text":7194,"children":7195},"示例 3：普通 main() 里写两个异步定时器",[7196,7197,7198,7199,7200],{"id":1103,"depth":88,"text":49},{"id":1134,"depth":88,"text":55},{"id":1621,"depth":88,"text":301},{"id":1658,"depth":88,"text":330},{"id":1692,"depth":88,"text":7201},"std::bind 里的固定参数",{"id":1760,"depth":80,"text":7203,"children":7204},"示例 4：普通 main() 里写重复定时器",[7205,7206,7207,7208,7209],{"id":1767,"depth":88,"text":49},{"id":1782,"depth":88,"text":55},{"id":2305,"depth":88,"text":301},{"id":2342,"depth":88,"text":330},{"id":2468,"depth":88,"text":2468},{"id":2514,"depth":80,"text":2515,"children":7211},[7212,7213,7214,7215,7216,7217],{"id":2518,"depth":88,"text":49},{"id":2533,"depth":88,"text":55},{"id":2973,"depth":88,"text":301},{"id":3001,"depth":88,"text":3001},{"id":3085,"depth":88,"text":3085},{"id":3172,"depth":88,"text":3172},{"id":3251,"depth":80,"text":3252,"children":7219},[7220,7221,7222,7223],{"id":3255,"depth":88,"text":49},{"id":3278,"depth":88,"text":55},{"id":3887,"depth":88,"text":301},{"id":3923,"depth":88,"text":330},{"id":3953,"depth":80,"text":7225,"children":7226},"示例 7：两个线程同时运行同一个 io_context",[7227,7228,7229,7230,7231],{"id":3959,"depth":88,"text":49},{"id":3977,"depth":88,"text":55},{"id":4603,"depth":88,"text":301},{"id":4627,"depth":88,"text":330},{"id":4652,"depth":88,"text":7232},"std::thread 里的 std::bind",{"id":4734,"depth":80,"text":7234,"children":7235},"示例 8：多线程下使用 strand 避免回调并发",[7236,7237,7238,7240,7242,7244,7245,7247,7248,7250,7251,7253],{"id":4742,"depth":88,"text":49},{"id":4883,"depth":88,"text":55},{"id":5833,"depth":88,"text":7239},"如果没有 strand 会发生什么",{"id":6041,"depth":88,"text":7241},"加上 strand 后发生什么",{"id":6205,"depth":88,"text":7243},"strand 不是“固定线程”",{"id":6279,"depth":88,"text":6280},{"id":6347,"depth":88,"text":7246},"为什么这里的 count_ 可以不用 mutex",{"id":6485,"depth":88,"text":6486},{"id":6597,"depth":88,"text":7249},"bind_executor() 是干什么的",{"id":6766,"depth":88,"text":301},{"id":6860,"depth":88,"text":7252},"strand 和 mutex 的思路有什么不同",{"id":6987,"depth":88,"text":6987},{"id":7073,"depth":80,"text":7073},"2100-0100-0100","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\u002F2100-0100-0100-ding-shi-qi-yu-yi-bu-io",{"title":5,"description":62},"wiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0100-定时器与异步IO","VAk4Qwr3NLIO2FlbzWYR73pSeFrYGgSakt84pwwnEZ4",[7268,7275,7281,7287,7293,7299,7305,7311,7317,7323,7329,7335,7341,7347,7353,7359,7365,7371,7377,7383,7389,7395,7401,7407,7413,7419,7425,7431,7437,7443,7449,7455,7461,7467,7473,7479,7485,7491,7497,7503,7509,7515,7521,7527,7533,7539,7545,7551,7557,7563,7569,7575,7580,7586,7592,7598,7604,7610,7616,7622,7628,7634,7639,7645,7651,7657,7663,7669,7675,7681,7687,7693,7699,7701,7707,7713,7719,7725,7731,7737,7743,7749,7755,7761,7767,7773,7779,7785,7791,7797,7803,7809],{"path":7269,"stem":7270,"title":7271,"authors":7272,"date":7256,"chapterOrder":7273,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7276,"stem":7277,"title":7278,"authors":7279,"date":7256,"chapterOrder":7280,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0200-c-ji-chu-chu-shi","wiki\u002F2023-10-05-Cplusplus教学\u002F0200-C++基础初识","C++基础初识",[7],"0200",{"path":7282,"stem":7283,"title":7284,"authors":7285,"date":7256,"chapterOrder":7286,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7288,"stem":7289,"title":7290,"authors":7291,"date":7256,"chapterOrder":7292,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0400-shu-ru-shu-chu","wiki\u002F2023-10-05-Cplusplus教学\u002F0400-输入输出","输入输出",[7],"0400",{"path":7294,"stem":7295,"title":7296,"authors":7297,"date":7256,"chapterOrder":7298,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0500-yun-suan-fu","wiki\u002F2023-10-05-Cplusplus教学\u002F0500-运算符","运算符",[7],"0500",{"path":7300,"stem":7301,"title":7302,"authors":7303,"date":7256,"chapterOrder":7304,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0600-cheng-xu-liu-cheng-jie-gou","wiki\u002F2023-10-05-Cplusplus教学\u002F0600-程序流程结构","程序流程结构",[7],"0600",{"path":7306,"stem":7307,"title":7308,"authors":7309,"date":7256,"chapterOrder":7310,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0700-shu-zu","wiki\u002F2023-10-05-Cplusplus教学\u002F0700-数组","数组",[7],"0700",{"path":7312,"stem":7313,"title":7314,"authors":7315,"date":7256,"chapterOrder":7316,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0800-han-shu-yu-tou-wen-jian","wiki\u002F2023-10-05-Cplusplus教学\u002F0800-函数与头文件","函数与头文件",[7],"0800",{"path":7318,"stem":7319,"title":7320,"authors":7321,"date":7256,"chapterOrder":7322,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0900-zhi-zhen","wiki\u002F2023-10-05-Cplusplus教学\u002F0900-指针","指针",[7],"0900",{"path":7324,"stem":7325,"title":7326,"authors":7327,"date":7256,"chapterOrder":7328,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1000-jie-gou-ti-yu-gong-yong-ti","wiki\u002F2023-10-05-Cplusplus教学\u002F1000-结构体与共用体","结构体与共用体",[7],"1000",{"path":7330,"stem":7331,"title":7332,"authors":7333,"date":7256,"chapterOrder":7334,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7336,"stem":7337,"title":7338,"authors":7339,"date":7256,"chapterOrder":7340,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1200-yin-yong","wiki\u002F2023-10-05-Cplusplus教学\u002F1200-引用","引用",[7],"1200",{"path":7342,"stem":7343,"title":7344,"authors":7345,"date":7256,"chapterOrder":7346,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1300-han-shu-ti-gao","wiki\u002F2023-10-05-Cplusplus教学\u002F1300-函数提高","函数提高",[7],"1300",{"path":7348,"stem":7349,"title":7350,"authors":7351,"date":7256,"chapterOrder":7352,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1350-ming-ming-kong-jian","wiki\u002F2023-10-05-Cplusplus教学\u002F1350-命名空间","命名空间",[7],"1350",{"path":7354,"stem":7355,"title":7356,"authors":7357,"date":7256,"chapterOrder":7358,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-0100-feng-zhuang","wiki\u002F2023-10-05-Cplusplus教学\u002F1400-0100-封装","封装",[7],"1400-0100",{"path":7360,"stem":7361,"title":7362,"authors":7363,"date":7256,"chapterOrder":7364,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7366,"stem":7367,"title":7368,"authors":7369,"date":7256,"chapterOrder":7370,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7372,"stem":7373,"title":7374,"authors":7375,"date":7256,"chapterOrder":7376,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7378,"stem":7379,"title":7380,"authors":7381,"date":7256,"chapterOrder":7382,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-0500-ji-cheng","wiki\u002F2023-10-05-Cplusplus教学\u002F1400-0500-继承","继承",[7],"1400-0500",{"path":7384,"stem":7385,"title":7386,"authors":7387,"date":7256,"chapterOrder":7388,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-0600-duo-tai","wiki\u002F2023-10-05-Cplusplus教学\u002F1400-0600-多态","多态",[7],"1400-0600",{"path":7390,"stem":7391,"title":7392,"authors":7393,"date":7256,"chapterOrder":7394,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-lei-he-dui-xiang","wiki\u002F2023-10-05-Cplusplus教学\u002F1400-类和对象","类和对象",[7],"1400",{"path":7396,"stem":7397,"title":7398,"authors":7399,"date":7256,"chapterOrder":7400,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1450-han-shu-zhi-zhen","wiki\u002F2023-10-05-Cplusplus教学\u002F1450-函数指针","函数指针",[7],"1450",{"path":7402,"stem":7403,"title":7404,"authors":7405,"date":7256,"chapterOrder":7406,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1500-wen-jian-cao-zuo","wiki\u002F2023-10-05-Cplusplus教学\u002F1500-文件操作","文件操作",[7],"1500",{"path":7408,"stem":7409,"title":7410,"authors":7411,"date":7256,"chapterOrder":7412,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7414,"stem":7415,"title":7416,"authors":7417,"date":7256,"chapterOrder":7418,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1700-mu-ban","wiki\u002F2023-10-05-Cplusplus教学\u002F1700-模板","模板",[7],"1700",{"path":7420,"stem":7421,"title":7422,"authors":7423,"date":7256,"chapterOrder":7424,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7426,"stem":7427,"title":7428,"authors":7429,"date":7256,"chapterOrder":7430,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7432,"stem":7433,"title":7434,"authors":7435,"date":7256,"chapterOrder":7436,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7438,"stem":7439,"title":7440,"authors":7441,"date":7256,"chapterOrder":7442,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7444,"stem":7445,"title":7446,"authors":7447,"date":7256,"chapterOrder":7448,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7450,"stem":7451,"title":7452,"authors":7453,"date":7256,"chapterOrder":7454,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7456,"stem":7457,"title":7458,"authors":7459,"date":7256,"chapterOrder":7460,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7462,"stem":7463,"title":7464,"authors":7465,"date":7256,"chapterOrder":7466,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7468,"stem":7469,"title":7470,"authors":7471,"date":7256,"chapterOrder":7472,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7474,"stem":7475,"title":7476,"authors":7477,"date":7256,"chapterOrder":7478,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7480,"stem":7481,"title":7482,"authors":7483,"date":7256,"chapterOrder":7484,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7486,"stem":7487,"title":7488,"authors":7489,"date":7256,"chapterOrder":7490,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-1200-chang-yong-suan-fa","wiki\u002F2023-10-05-Cplusplus教学\u002F1800-1200-常用算法","常用算法",[7],"1800-1200",{"path":7492,"stem":7493,"title":7494,"authors":7495,"date":7256,"chapterOrder":7496,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-stl-ti-gao-bian-cheng","wiki\u002F2023-10-05-Cplusplus教学\u002F1800-STL提高编程","STL提高编程",[7],"1800",{"path":7498,"stem":7499,"title":7500,"authors":7501,"date":7256,"chapterOrder":7502,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1900-c-lei-xing-zhuan-huan","wiki\u002F2023-10-05-Cplusplus教学\u002F1900-C++类型转换","C++类型转换",[7],"1900",{"path":7504,"stem":7505,"title":7506,"authors":7507,"date":7256,"chapterOrder":7508,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0100-auto","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-0100-auto","auto",[7],"2000-0100",{"path":7510,"stem":7511,"title":7512,"authors":7513,"date":7256,"chapterOrder":7514,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0200-nullptr","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-0200-nullptr","nullptr",[7],"2000-0200",{"path":7516,"stem":7517,"title":7518,"authors":7519,"date":7256,"chapterOrder":7520,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0300-using","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-0300-using","using",[7],"2000-0300",{"path":7522,"stem":7523,"title":7524,"authors":7525,"date":7256,"chapterOrder":7526,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7528,"stem":7529,"title":7530,"authors":7531,"date":7256,"chapterOrder":7532,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7534,"stem":7535,"title":7536,"authors":7537,"date":7256,"chapterOrder":7538,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7540,"stem":7541,"title":7542,"authors":7543,"date":7256,"chapterOrder":7544,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0700-constexpr","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-0700-constexpr","constexpr",[7],"2000-0700",{"path":7546,"stem":7547,"title":7548,"authors":7549,"date":7256,"chapterOrder":7550,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0800-raii","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-0800-RAII","RAII",[7],"2000-0800",{"path":7552,"stem":7553,"title":7554,"authors":7555,"date":7256,"chapterOrder":7556,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0900-zhi-neng-zhi-zhen","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-0900-智能指针","智能指针",[7],"2000-0900",{"path":7558,"stem":7559,"title":7560,"authors":7561,"date":7256,"chapterOrder":7562,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7564,"stem":7565,"title":7566,"authors":7567,"date":7256,"chapterOrder":7568,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7570,"stem":7571,"title":7572,"authors":7573,"date":7256,"chapterOrder":7574,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7576,"stem":7577,"title":32,"authors":7578,"date":7256,"chapterOrder":7579,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1300-std-bind","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1300-std-bind",[7],"2000-1300",{"path":7581,"stem":7582,"title":7583,"authors":7584,"date":7256,"chapterOrder":7585,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7587,"stem":7588,"title":7589,"authors":7590,"date":7256,"chapterOrder":7591,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7593,"stem":7594,"title":7595,"authors":7596,"date":7256,"chapterOrder":7597,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7599,"stem":7600,"title":7601,"authors":7602,"date":7256,"chapterOrder":7603,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7605,"stem":7606,"title":7607,"authors":7608,"date":7256,"chapterOrder":7609,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7611,"stem":7612,"title":7613,"authors":7614,"date":7256,"chapterOrder":7615,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7617,"stem":7618,"title":7619,"authors":7620,"date":7256,"chapterOrder":7621,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7623,"stem":7624,"title":7625,"authors":7626,"date":7256,"chapterOrder":7627,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7629,"stem":7630,"title":7631,"authors":7632,"date":7256,"chapterOrder":7633,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7635,"stem":7636,"title":4655,"authors":7637,"date":7256,"chapterOrder":7638,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7640,"stem":7641,"title":7642,"authors":7643,"date":7256,"chapterOrder":7644,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7646,"stem":7647,"title":7648,"authors":7649,"date":7256,"chapterOrder":7650,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7652,"stem":7653,"title":7654,"authors":7655,"date":7256,"chapterOrder":7656,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7658,"stem":7659,"title":7660,"authors":7661,"date":7256,"chapterOrder":7662,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7664,"stem":7665,"title":7666,"authors":7667,"date":7256,"chapterOrder":7668,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-1600-jthread-stop-token","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-1600-jthread-stop-token","jthread 与 stop_token",[7],"2000-1900-1600",{"path":7670,"stem":7671,"title":7672,"authors":7673,"date":7256,"chapterOrder":7674,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7676,"stem":7677,"title":7678,"authors":7679,"date":7256,"chapterOrder":7680,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7682,"stem":7683,"title":7684,"authors":7685,"date":7256,"chapterOrder":7686,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7688,"stem":7689,"title":7690,"authors":7691,"date":7256,"chapterOrder":7692,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7694,"stem":7695,"title":7696,"authors":7697,"date":7256,"chapterOrder":7698,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-xian-dai-c","wiki\u002F2023-10-05-Cplusplus教学\u002F2000-现代C++","现代C++",[7],"2000",{"path":7263,"stem":7265,"title":5,"authors":7700,"date":7256,"chapterOrder":7255,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},[7],{"path":7702,"stem":7703,"title":7704,"authors":7705,"date":7256,"chapterOrder":7706,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7708,"stem":7709,"title":7710,"authors":7711,"date":7256,"chapterOrder":7712,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7714,"stem":7715,"title":7716,"authors":7717,"date":7256,"chapterOrder":7718,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7720,"stem":7721,"title":7722,"authors":7723,"date":7256,"chapterOrder":7724,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7726,"stem":7727,"title":7728,"authors":7729,"date":7256,"chapterOrder":7730,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7732,"stem":7733,"title":7734,"authors":7735,"date":7256,"chapterOrder":7736,"chapterDepth":80,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7738,"stem":7739,"title":7740,"authors":7741,"date":7256,"chapterOrder":7742,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7744,"stem":7745,"title":7746,"authors":7747,"date":7256,"chapterOrder":7748,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7750,"stem":7751,"title":7752,"authors":7753,"date":7256,"chapterOrder":7754,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7756,"stem":7757,"title":7758,"authors":7759,"date":7256,"chapterOrder":7760,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7762,"stem":7763,"title":7764,"authors":7765,"date":7256,"chapterOrder":7766,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7768,"stem":7769,"title":7770,"authors":7771,"date":7256,"chapterOrder":7772,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-chang-yong-ku","wiki\u002F2023-10-05-Cplusplus教学\u002F2100-常用库","常用库学习",[7],"2100",{"path":7774,"stem":7775,"title":7776,"authors":7777,"date":7256,"chapterOrder":7778,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7780,"stem":7781,"title":7782,"authors":7783,"date":7256,"chapterOrder":7784,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7786,"stem":7787,"title":7788,"authors":7789,"date":7256,"chapterOrder":7790,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7792,"stem":7793,"title":7794,"authors":7795,"date":7256,"chapterOrder":7796,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7798,"stem":7799,"title":7800,"authors":7801,"date":7256,"chapterOrder":7802,"chapterDepth":69,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\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":7804,"stem":7805,"title":7806,"authors":7807,"date":7256,"chapterOrder":7808,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":7261},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2200-cmake-gong-cheng-mu-ban","wiki\u002F2023-10-05-Cplusplus教学\u002F2200-CMake工程模板","CMake工程模板",[7],"2200",{"path":7258,"stem":7810,"title":7811,"authors":7812,"date":7256,"chapterOrder":7813,"chapterDepth":7274,"docKey":7257,"docRoot":7258,"docTitle":7259,"isWikiDoc":99,"isWikiIndex":99},"wiki\u002F2023-10-05-Cplusplus教学\u002Findex","C\u002FC++教程",[7],null,[7815,7817,7820,7823],{"name":7,"image":7816},"\u002Fimages\u002Fmember_photo\u002F董佳辉.jpg",{"name":7818,"image":7819},"宫金良","\u002Fimages\u002Fmember_photo\u002F宫金良.jpg",{"name":7821,"image":7822},"巩丽","\u002Fimages\u002Fmember_photo\u002F巩丽.png",{"name":7824,"image":7825},"张彦斐","\u002Fimages\u002Fmember_photo\u002F张彦斐.jpg",1792431899611]