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