[{"data":1,"prerenderedAt":2864},["ShallowReactive",2],{"post-\u002Fposts\u002Fcpp-concurrency-basics":3,"all-posts-nav":2592},{"id":4,"title":5,"body":6,"categories":2577,"date":2579,"description":12,"draft":2580,"extension":2581,"hidden":2580,"meta":2582,"navigation":57,"path":2583,"published":2580,"seo":2584,"stem":2585,"tags":2586,"__hash__":2591},"posts\u002Fposts\u002Fcpp-concurrency-basics.md","C++ 并发编程入门：从数据竞争到线程池",{"type":7,"value":8,"toc":2565},"minimark",[9,13,18,21,246,249,257,260,266,272,278,281,287,294,297,300,305,308,365,368,402,406,409,462,465,471,475,478,555,558,568,572,575,578,606,613,695,700,765,768,773,780,785,791,796,802,804,808,811,816,833,838,853,1403,1408,1426,1428,1432,1435,1440,1451,1454,1459,1465,1470,2291,2296,2464,2469,2475,2481,2487,2492,2498,2500,2503,2506,2511,2522,2527,2538,2543,2554,2561],[10,11,12],"p",{},"量化开发面试必考并发编程，但很多人第一次接触就直接看线程池代码，结果一头雾水。这篇文章从最基础的数据竞争开始，一步步推导出有界阻塞队列和线程池，每个概念都从\"它解决什么问题\"出发。",[14,15,17],"h2",{"id":16},"第一课数据竞争","第一课：数据竞争",[10,19,20],{},"先看这段代码，猜一下输出是什么：",[22,23,28],"pre",{"className":24,"code":25,"language":26,"meta":27,"style":27},"language-cpp shiki shiki-themes github-dark-dimmed github-light","#include \u003Ciostream>\n#include \u003Cthread>\n\nint counter = 0;\n\nvoid add() {\n    for (int i = 0; i \u003C 100000; i++) {\n        counter++;\n    }\n}\n\nint main() {\n    std::thread t1(add);\n    std::thread t2(add);\n    t1.join();\n    t2.join();\n    std::cout \u003C\u003C counter \u003C\u003C std::endl;\n}\n","cpp","",[29,30,31,44,52,59,79,84,97,133,143,149,155,160,170,186,198,210,220,241],"code",{"__ignoreMap":27},[32,33,36,40],"span",{"class":34,"line":35},"line",1,[32,37,39],{"class":38},"s6PUj","#include",[32,41,43],{"class":42},"sXfbr"," \u003Ciostream>\n",[32,45,47,49],{"class":34,"line":46},2,[32,48,39],{"class":38},[32,50,51],{"class":42}," \u003Cthread>\n",[32,53,55],{"class":34,"line":54},3,[32,56,58],{"emptyLinePlaceholder":57},true,"\n",[32,60,62,65,69,72,76],{"class":34,"line":61},4,[32,63,64],{"class":38},"int",[32,66,68],{"class":67},"ssh_m"," counter ",[32,70,71],{"class":38},"=",[32,73,75],{"class":74},"swcJU"," 0",[32,77,78],{"class":67},";\n",[32,80,82],{"class":34,"line":81},5,[32,83,58],{"emptyLinePlaceholder":57},[32,85,87,90,94],{"class":34,"line":86},6,[32,88,89],{"class":38},"void",[32,91,93],{"class":92},"saVmf"," add",[32,95,96],{"class":67},"() {\n",[32,98,100,103,106,108,111,113,115,118,121,124,127,130],{"class":34,"line":99},7,[32,101,102],{"class":38},"    for",[32,104,105],{"class":67}," (",[32,107,64],{"class":38},[32,109,110],{"class":67}," i ",[32,112,71],{"class":38},[32,114,75],{"class":74},[32,116,117],{"class":67},"; i ",[32,119,120],{"class":38},"\u003C",[32,122,123],{"class":74}," 100000",[32,125,126],{"class":67},"; i",[32,128,129],{"class":38},"++",[32,131,132],{"class":67},") {\n",[32,134,136,139,141],{"class":34,"line":135},8,[32,137,138],{"class":67},"        counter",[32,140,129],{"class":38},[32,142,78],{"class":67},[32,144,146],{"class":34,"line":145},9,[32,147,148],{"class":67},"    }\n",[32,150,152],{"class":34,"line":151},10,[32,153,154],{"class":67},"}\n",[32,156,158],{"class":34,"line":157},11,[32,159,58],{"emptyLinePlaceholder":57},[32,161,163,165,168],{"class":34,"line":162},12,[32,164,64],{"class":38},[32,166,167],{"class":92}," main",[32,169,96],{"class":67},[32,171,173,177,180,183],{"class":34,"line":172},13,[32,174,176],{"class":175},"sqRhv","    std",[32,178,179],{"class":67},"::thread ",[32,181,182],{"class":92},"t1",[32,184,185],{"class":67},"(add);\n",[32,187,189,191,193,196],{"class":34,"line":188},14,[32,190,176],{"class":175},[32,192,179],{"class":67},[32,194,195],{"class":92},"t2",[32,197,185],{"class":67},[32,199,201,204,207],{"class":34,"line":200},15,[32,202,203],{"class":67},"    t1.",[32,205,206],{"class":92},"join",[32,208,209],{"class":67},"();\n",[32,211,213,216,218],{"class":34,"line":212},16,[32,214,215],{"class":67},"    t2.",[32,217,206],{"class":92},[32,219,209],{"class":67},[32,221,223,225,228,231,233,235,238],{"class":34,"line":222},17,[32,224,176],{"class":175},[32,226,227],{"class":67},"::cout ",[32,229,230],{"class":38},"\u003C\u003C",[32,232,68],{"class":67},[32,234,230],{"class":38},[32,236,237],{"class":175}," std",[32,239,240],{"class":67},"::endl;\n",[32,242,244],{"class":34,"line":243},18,[32,245,154],{"class":67},[10,247,248],{},"两个线程各加 10 万次，直觉上应该输出 200000。实际运行：",[22,250,255],{"className":251,"code":253,"language":254},[252],"language-text","131072\n118934\n157823\n","text",[29,256,253],{"__ignoreMap":27},[10,258,259],{},"每次都不一样，几乎从来不是 200000。",[10,261,262],{},[263,264,265],"strong",{},"为什么？",[10,267,268,271],{},[29,269,270],{},"counter++"," 看起来是一行，但 CPU 实际执行是三步：",[22,273,276],{"className":274,"code":275,"language":254},[252],"1. 把 counter 从内存读到寄存器   (READ)\n2. 寄存器里的值 +1              (ADD)\n3. 把寄存器的值写回内存          (WRITE)\n",[29,277,275],{"__ignoreMap":27},[10,279,280],{},"两个线程同时跑，可能发生这种情况：",[22,282,285],{"className":283,"code":284,"language":254},[252],"时间线      线程1                线程2\n────────────────────────────────────────\nt1          READ  → 拿到 100\nt2                               READ  → 也拿到 100  ← 还没被写回！\nt3          ADD   → 算出 101\nt4                               ADD   → 也算出 101\nt5          WRITE → 写回 101\nt6                               WRITE → 写回 101    ← 覆盖了！\n",[29,286,284],{"__ignoreMap":27},[10,288,289,290,293],{},"两个线程各加了一次，但 counter 只从 100 变成 101，丢了一次加法。这就叫",[263,291,292],{},"数据竞争（Data Race）","。",[295,296],"hr",{},[14,298,299],{"id":299},"四个核心工具",[301,302,304],"h3",{"id":303},"_1-mutex","1. mutex",[10,306,307],{},"本质：一把锁，同一时刻只有一个线程能持有它。",[22,309,311],{"className":24,"code":310,"language":26,"meta":27,"style":27},"std::mutex mtx;\n\nmtx.lock();    \u002F\u002F 拿锁，拿不到就在这里阻塞等待\ncounter++;     \u002F\u002F 现在只有我一个线程在这里\nmtx.unlock();  \u002F\u002F 还锁\n",[29,312,313,321,325,340,353],{"__ignoreMap":27},[32,314,315,318],{"class":34,"line":35},[32,316,317],{"class":175},"std",[32,319,320],{"class":67},"::mutex mtx;\n",[32,322,323],{"class":34,"line":46},[32,324,58],{"emptyLinePlaceholder":57},[32,326,327,330,333,336],{"class":34,"line":54},[32,328,329],{"class":67},"mtx.",[32,331,332],{"class":92},"lock",[32,334,335],{"class":67},"();",[32,337,339],{"class":338},"sgHix","    \u002F\u002F 拿锁，拿不到就在这里阻塞等待\n",[32,341,342,345,347,350],{"class":34,"line":61},[32,343,344],{"class":67},"counter",[32,346,129],{"class":38},[32,348,349],{"class":67},";",[32,351,352],{"class":338},"     \u002F\u002F 现在只有我一个线程在这里\n",[32,354,355,357,360,362],{"class":34,"line":81},[32,356,329],{"class":67},[32,358,359],{"class":92},"unlock",[32,361,335],{"class":67},[32,363,364],{"class":338},"  \u002F\u002F 还锁\n",[10,366,367],{},"问题是手动 lock\u002Funlock 很危险：",[22,369,371],{"className":24,"code":370,"language":26,"meta":27,"style":27},"mtx.lock();\ndoSomething();  \u002F\u002F 如果这里抛异常\nmtx.unlock();   \u002F\u002F 永远不会执行 → 死锁\n",[29,372,373,381,391],{"__ignoreMap":27},[32,374,375,377,379],{"class":34,"line":35},[32,376,329],{"class":67},[32,378,332],{"class":92},[32,380,209],{"class":67},[32,382,383,386,388],{"class":34,"line":46},[32,384,385],{"class":92},"doSomething",[32,387,335],{"class":67},[32,389,390],{"class":338},"  \u002F\u002F 如果这里抛异常\n",[32,392,393,395,397,399],{"class":34,"line":54},[32,394,329],{"class":67},[32,396,359],{"class":92},[32,398,335],{"class":67},[32,400,401],{"class":338},"   \u002F\u002F 永远不会执行 → 死锁\n",[301,403,405],{"id":404},"_2-lock_guard","2. lock_guard",[10,407,408],{},"本质：一个对象，构造时加锁，析构时自动解锁。",[22,410,412],{"className":24,"code":411,"language":26,"meta":27,"style":27},"{\n    std::lock_guard\u003Cstd::mutex> lock(mtx);  \u002F\u002F 构造 → 加锁\n    counter++;\n}  \u002F\u002F 离开大括号 → lock 析构 → 自动解锁\n",[29,413,414,419,445,454],{"__ignoreMap":27},[32,415,416],{"class":34,"line":35},[32,417,418],{"class":67},"{\n",[32,420,421,423,426,428,430,433,436,439,442],{"class":34,"line":46},[32,422,176],{"class":175},[32,424,425],{"class":67},"::lock_guard",[32,427,120],{"class":38},[32,429,317],{"class":175},[32,431,432],{"class":67},"::mutex",[32,434,435],{"class":38},">",[32,437,438],{"class":92}," lock",[32,440,441],{"class":67},"(mtx);",[32,443,444],{"class":338},"  \u002F\u002F 构造 → 加锁\n",[32,446,447,450,452],{"class":34,"line":54},[32,448,449],{"class":67},"    counter",[32,451,129],{"class":38},[32,453,78],{"class":67},[32,455,456,459],{"class":34,"line":61},[32,457,458],{"class":67},"}",[32,460,461],{"class":338},"  \u002F\u002F 离开大括号 → lock 析构 → 自动解锁\n",[10,463,464],{},"利用 C++ 的 RAII：对象销毁时自动执行清理。不管正常退出还是异常，析构函数一定执行，锁一定释放。",[10,466,467,470],{},[263,468,469],{},"局限："," 加锁后不能中途解锁，整个生命周期都是锁定状态。",[301,472,474],{"id":473},"_3-unique_lock","3. unique_lock",[10,476,477],{},"本质：比 lock_guard 更灵活，可以中途解锁\u002F重新加锁。",[22,479,481],{"className":24,"code":480,"language":26,"meta":27,"style":27},"std::unique_lock\u003Cstd::mutex> lock(mtx);  \u002F\u002F 构造 → 加锁\n\nlock.unlock();   \u002F\u002F 中途解锁\n\u002F\u002F ... 做一些不需要锁的事\nlock.lock();     \u002F\u002F 重新加锁\n\u002F\u002F 析构时如果还持有锁，自动解锁\n",[29,482,483,518,522,534,539,550],{"__ignoreMap":27},[32,484,485,487,490,493,495,497,499,502,505,507,510,513,516],{"class":34,"line":35},[32,486,317],{"class":175},[32,488,489],{"class":67},"::",[32,491,492],{"class":175},"unique_lock",[32,494,120],{"class":67},[32,496,317],{"class":175},[32,498,489],{"class":67},[32,500,501],{"class":175},"mutex",[32,503,504],{"class":67},"> ",[32,506,332],{"class":92},[32,508,509],{"class":67},"(",[32,511,512],{"class":175},"mtx",[32,514,515],{"class":67},");",[32,517,444],{"class":338},[32,519,520],{"class":34,"line":46},[32,521,58],{"emptyLinePlaceholder":57},[32,523,524,527,529,531],{"class":34,"line":54},[32,525,526],{"class":67},"lock.",[32,528,359],{"class":92},[32,530,335],{"class":67},[32,532,533],{"class":338},"   \u002F\u002F 中途解锁\n",[32,535,536],{"class":34,"line":61},[32,537,538],{"class":338},"\u002F\u002F ... 做一些不需要锁的事\n",[32,540,541,543,545,547],{"class":34,"line":81},[32,542,526],{"class":67},[32,544,332],{"class":92},[32,546,335],{"class":67},[32,548,549],{"class":338},"     \u002F\u002F 重新加锁\n",[32,551,552],{"class":34,"line":86},[32,553,554],{"class":338},"\u002F\u002F 析构时如果还持有锁，自动解锁\n",[10,556,557],{},"只有两种情况必须用 unique_lock：",[559,560,561,565],"ol",{},[562,563,564],"li",{},"需要配合 condition_variable（cv.wait 内部需要中途解锁）",[562,566,567],{},"需要在持有锁期间手动解锁",[301,569,571],{"id":570},"_4-condition_variable","4. condition_variable",[10,573,574],{},"mutex 只能解决\"同时访问\"的问题，解决不了\"等待某个条件\"的问题。",[10,576,577],{},"比如\"队列空时，取数据的线程要等待\"，用 mutex 的朴素想法是：",[22,579,581],{"className":24,"code":580,"language":26,"meta":27,"style":27},"while (queue.empty()) {\n    \u002F\u002F 空转等待？← 线程一直占着 CPU，非常浪费\n}\n",[29,582,583,597,602],{"__ignoreMap":27},[32,584,585,588,591,594],{"class":34,"line":35},[32,586,587],{"class":38},"while",[32,589,590],{"class":67}," (queue.",[32,592,593],{"class":92},"empty",[32,595,596],{"class":67},"()) {\n",[32,598,599],{"class":34,"line":46},[32,600,601],{"class":338},"    \u002F\u002F 空转等待？← 线程一直占着 CPU，非常浪费\n",[32,603,604],{"class":34,"line":54},[32,605,154],{"class":67},[10,607,608,609,612],{},"这叫",[263,610,611],{},"忙等（busy waiting）","。condition_variable 解决这个问题：",[22,614,616],{"className":24,"code":615,"language":26,"meta":27,"style":27},"std::condition_variable cv;\n\n\u002F\u002F 等待方\ncv.wait(lock, [] { return !queue.empty(); });  \u002F\u002F 条件不满足就睡觉\n\n\u002F\u002F 通知方\ncv.notify_one();   \u002F\u002F 叫醒一个等待的线程\ncv.notify_all();   \u002F\u002F 叫醒所有等待的线程\n",[29,617,618,625,629,634,662,666,671,683],{"__ignoreMap":27},[32,619,620,622],{"class":34,"line":35},[32,621,317],{"class":175},[32,623,624],{"class":67},"::condition_variable cv;\n",[32,626,627],{"class":34,"line":46},[32,628,58],{"emptyLinePlaceholder":57},[32,630,631],{"class":34,"line":54},[32,632,633],{"class":338},"\u002F\u002F 等待方\n",[32,635,636,639,642,645,648,651,654,656,659],{"class":34,"line":61},[32,637,638],{"class":67},"cv.",[32,640,641],{"class":92},"wait",[32,643,644],{"class":67},"(lock, [] { ",[32,646,647],{"class":38},"return",[32,649,650],{"class":38}," !",[32,652,653],{"class":67},"queue.",[32,655,593],{"class":92},[32,657,658],{"class":67},"(); });",[32,660,661],{"class":338},"  \u002F\u002F 条件不满足就睡觉\n",[32,663,664],{"class":34,"line":81},[32,665,58],{"emptyLinePlaceholder":57},[32,667,668],{"class":34,"line":86},[32,669,670],{"class":338},"\u002F\u002F 通知方\n",[32,672,673,675,678,680],{"class":34,"line":99},[32,674,638],{"class":67},[32,676,677],{"class":92},"notify_one",[32,679,335],{"class":67},[32,681,682],{"class":338},"   \u002F\u002F 叫醒一个等待的线程\n",[32,684,685,687,690,692],{"class":34,"line":135},[32,686,638],{"class":67},[32,688,689],{"class":92},"notify_all",[32,691,335],{"class":67},[32,693,694],{"class":338},"   \u002F\u002F 叫醒所有等待的线程\n",[10,696,697],{},[263,698,699],{},"wait 内部到底发生了什么：",[22,701,703],{"className":24,"code":702,"language":26,"meta":27,"style":27},"\u002F\u002F cv.wait(lock, pred) 等价于：\nwhile (!pred()) {\n    mtx.unlock();   \u002F\u002F 解锁，让别人能放数据\n    \u002F\u002F 线程进入睡眠...\n    \u002F\u002F 被 notify 唤醒...\n    mtx.lock();     \u002F\u002F 重新加锁\n}\n\u002F\u002F 条件满足，继续执行\n",[29,704,705,710,724,736,741,746,756,760],{"__ignoreMap":27},[32,706,707],{"class":34,"line":35},[32,708,709],{"class":338},"\u002F\u002F cv.wait(lock, pred) 等价于：\n",[32,711,712,714,716,719,722],{"class":34,"line":46},[32,713,587],{"class":38},[32,715,105],{"class":67},[32,717,718],{"class":38},"!",[32,720,721],{"class":92},"pred",[32,723,596],{"class":67},[32,725,726,729,731,733],{"class":34,"line":54},[32,727,728],{"class":67},"    mtx.",[32,730,359],{"class":92},[32,732,335],{"class":67},[32,734,735],{"class":338},"   \u002F\u002F 解锁，让别人能放数据\n",[32,737,738],{"class":34,"line":61},[32,739,740],{"class":338},"    \u002F\u002F 线程进入睡眠...\n",[32,742,743],{"class":34,"line":81},[32,744,745],{"class":338},"    \u002F\u002F 被 notify 唤醒...\n",[32,747,748,750,752,754],{"class":34,"line":86},[32,749,728],{"class":67},[32,751,332],{"class":92},[32,753,335],{"class":67},[32,755,549],{"class":338},[32,757,758],{"class":34,"line":99},[32,759,154],{"class":67},[32,761,762],{"class":34,"line":135},[32,763,764],{"class":338},"\u002F\u002F 条件满足，继续执行\n",[10,766,767],{},"为什么必须先解锁再睡？如果持有锁去睡觉，生产者永远拿不到锁放数据，消费者永远不会被唤醒——死锁。",[10,769,770],{},[263,771,772],{},"为什么 wait 要传 lambda：",[10,774,775,776,779],{},"操作系统存在",[263,777,778],{},"虚假唤醒","：线程没有被 notify，却自己醒了。不传 lambda 的话醒来队列可能还是空的就去取数据，直接崩。lambda 保证醒来条件一定为真。",[10,781,782],{},[263,783,784],{},"四者关系：",[22,786,789],{"className":787,"code":788,"language":254},[252],"mutex\n  │ 太危险，需要自动管理\n  ▼\nlock_guard          ← 够用就用这个\n  │ 需要中途解锁时\n  ▼\nunique_lock         ← 配合 cv 时必须用这个\n  │ 需要等待条件时\n  ▼\ncondition_variable  ← wait\u002Fnotify，线程间协调\n",[29,790,788],{"__ignoreMap":27},[10,792,793],{},[263,794,795],{},"一句话记忆：",[22,797,800],{"className":798,"code":799,"language":254},[252],"mutex          → 门上的锁\nlock_guard     → 进门自动锁，出门自动开（钥匙绑在脚上）\nunique_lock    → 同上，但可以临时把钥匙摘下来\ncv.wait        → 我先把钥匙放门口，去睡觉，有人叫我再来拿\ncv.notify_one  → 喂，你可以来拿钥匙了\n",[29,801,799],{"__ignoreMap":27},[295,803],{},[14,805,807],{"id":806},"实战一有界阻塞队列","实战一：有界阻塞队列",[10,809,810],{},"理解了四个工具，阻塞队列就是把它们组合起来。",[10,812,813],{},[263,814,815],{},"push 的逻辑：",[559,817,818,821,824,827,830],{},[562,819,820],{},"加锁",[562,822,823],{},"如果队列满了，等待（not_full 条件变量）",[562,825,826],{},"放入数据",[562,828,829],{},"通知等待取数据的线程（not_empty）",[562,831,832],{},"解锁",[10,834,835],{},[263,836,837],{},"pop 的逻辑：",[559,839,840,842,845,848,851],{},[562,841,820],{},[562,843,844],{},"如果队列空了，等待（not_empty 条件变量）",[562,846,847],{},"取出数据",[562,849,850],{},"通知等待放数据的线程（not_full）",[562,852,832],{},[22,854,856],{"className":24,"code":855,"language":26,"meta":27,"style":27},"#include \u003Cqueue>\n#include \u003Cmutex>\n#include \u003Ccondition_variable>\n\ntemplate\u003Ctypename T>\nclass BoundedBlockingQueue {\npublic:\n    explicit BoundedBlockingQueue(size_t capacity)\n        : capacity_(capacity) {}\n\n    void push(T val) {\n        std::unique_lock\u003Cstd::mutex> lock(mutex_);\n        not_full_.wait(lock, [this] { return queue_.size() \u003C capacity_; });\n        queue_.push(std::move(val));\n        not_empty_.notify_one();\n    }\n\n    void pop(T& val) {\n        std::unique_lock\u003Cstd::mutex> lock(mutex_);\n        not_empty_.wait(lock, [this] { return !queue_.empty(); });\n        val = std::move(queue_.front());\n        queue_.pop();\n        not_full_.notify_one();\n    }\n\n    bool try_push(T val) {\n        std::unique_lock\u003Cstd::mutex> lock(mutex_);\n        if (queue_.size() >= capacity_) return false;\n        queue_.push(std::move(val));\n        not_empty_.notify_one();\n        return true;\n    }\n\n    size_t size() const {\n        std::unique_lock\u003Cstd::mutex> lock(mutex_);\n        return queue_.size();\n    }\n\nprivate:\n    size_t capacity_;\n    std::queue\u003CT> queue_;\n    mutable std::mutex mutex_;       \u002F\u002F mutable：const 方法里也能加锁\n    std::condition_variable not_full_;\n    std::condition_variable not_empty_;\n};\n",[29,857,858,865,872,879,883,899,910,915,934,945,949,967,988,1020,1040,1049,1053,1057,1075,1094,1119,1142,1152,1161,1166,1171,1188,1207,1233,1250,1259,1270,1275,1280,1296,1315,1326,1331,1336,1342,1350,1367,1381,1389,1397],{"__ignoreMap":27},[32,859,860,862],{"class":34,"line":35},[32,861,39],{"class":38},[32,863,864],{"class":42}," \u003Cqueue>\n",[32,866,867,869],{"class":34,"line":46},[32,868,39],{"class":38},[32,870,871],{"class":42}," \u003Cmutex>\n",[32,873,874,876],{"class":34,"line":54},[32,875,39],{"class":38},[32,877,878],{"class":42}," \u003Ccondition_variable>\n",[32,880,881],{"class":34,"line":61},[32,882,58],{"emptyLinePlaceholder":57},[32,884,885,888,890,893,896],{"class":34,"line":81},[32,886,887],{"class":38},"template",[32,889,120],{"class":67},[32,891,892],{"class":38},"typename",[32,894,895],{"class":175}," T",[32,897,898],{"class":67},">\n",[32,900,901,904,907],{"class":34,"line":86},[32,902,903],{"class":38},"class",[32,905,906],{"class":175}," BoundedBlockingQueue",[32,908,909],{"class":67}," {\n",[32,911,912],{"class":34,"line":99},[32,913,914],{"class":38},"public:\n",[32,916,917,920,922,924,927,931],{"class":34,"line":135},[32,918,919],{"class":38},"    explicit",[32,921,906],{"class":92},[32,923,509],{"class":67},[32,925,926],{"class":38},"size_t",[32,928,930],{"class":929},"sNjOc"," capacity",[32,932,933],{"class":67},")\n",[32,935,936,939,942],{"class":34,"line":145},[32,937,938],{"class":67},"        : ",[32,940,941],{"class":92},"capacity_",[32,943,944],{"class":67},"(capacity) {}\n",[32,946,947],{"class":34,"line":151},[32,948,58],{"emptyLinePlaceholder":57},[32,950,951,954,957,959,962,965],{"class":34,"line":157},[32,952,953],{"class":38},"    void",[32,955,956],{"class":92}," push",[32,958,509],{"class":67},[32,960,961],{"class":175},"T",[32,963,964],{"class":929}," val",[32,966,132],{"class":67},[32,968,969,972,975,977,979,981,983,985],{"class":34,"line":162},[32,970,971],{"class":175},"        std",[32,973,974],{"class":67},"::unique_lock",[32,976,120],{"class":38},[32,978,317],{"class":175},[32,980,432],{"class":67},[32,982,435],{"class":38},[32,984,438],{"class":92},[32,986,987],{"class":67},"(mutex_);\n",[32,989,990,993,995,998,1001,1004,1006,1009,1012,1015,1017],{"class":34,"line":172},[32,991,992],{"class":67},"        not_full_.",[32,994,641],{"class":92},[32,996,997],{"class":67},"(lock, [",[32,999,1000],{"class":74},"this",[32,1002,1003],{"class":67},"] { ",[32,1005,647],{"class":38},[32,1007,1008],{"class":67}," queue_.",[32,1010,1011],{"class":92},"size",[32,1013,1014],{"class":67},"() ",[32,1016,120],{"class":38},[32,1018,1019],{"class":67}," capacity_; });\n",[32,1021,1022,1025,1028,1030,1032,1034,1037],{"class":34,"line":188},[32,1023,1024],{"class":67},"        queue_.",[32,1026,1027],{"class":92},"push",[32,1029,509],{"class":67},[32,1031,317],{"class":175},[32,1033,489],{"class":67},[32,1035,1036],{"class":92},"move",[32,1038,1039],{"class":67},"(val));\n",[32,1041,1042,1045,1047],{"class":34,"line":200},[32,1043,1044],{"class":67},"        not_empty_.",[32,1046,677],{"class":92},[32,1048,209],{"class":67},[32,1050,1051],{"class":34,"line":212},[32,1052,148],{"class":67},[32,1054,1055],{"class":34,"line":222},[32,1056,58],{"emptyLinePlaceholder":57},[32,1058,1059,1061,1064,1066,1068,1071,1073],{"class":34,"line":243},[32,1060,953],{"class":38},[32,1062,1063],{"class":92}," pop",[32,1065,509],{"class":67},[32,1067,961],{"class":175},[32,1069,1070],{"class":38},"&",[32,1072,964],{"class":929},[32,1074,132],{"class":67},[32,1076,1078,1080,1082,1084,1086,1088,1090,1092],{"class":34,"line":1077},19,[32,1079,971],{"class":175},[32,1081,974],{"class":67},[32,1083,120],{"class":38},[32,1085,317],{"class":175},[32,1087,432],{"class":67},[32,1089,435],{"class":38},[32,1091,438],{"class":92},[32,1093,987],{"class":67},[32,1095,1097,1099,1101,1103,1105,1107,1109,1111,1114,1116],{"class":34,"line":1096},20,[32,1098,1044],{"class":67},[32,1100,641],{"class":92},[32,1102,997],{"class":67},[32,1104,1000],{"class":74},[32,1106,1003],{"class":67},[32,1108,647],{"class":38},[32,1110,650],{"class":38},[32,1112,1113],{"class":67},"queue_.",[32,1115,593],{"class":92},[32,1117,1118],{"class":67},"(); });\n",[32,1120,1122,1125,1127,1129,1131,1133,1136,1139],{"class":34,"line":1121},21,[32,1123,1124],{"class":67},"        val ",[32,1126,71],{"class":38},[32,1128,237],{"class":175},[32,1130,489],{"class":67},[32,1132,1036],{"class":92},[32,1134,1135],{"class":67},"(queue_.",[32,1137,1138],{"class":92},"front",[32,1140,1141],{"class":67},"());\n",[32,1143,1145,1147,1150],{"class":34,"line":1144},22,[32,1146,1024],{"class":67},[32,1148,1149],{"class":92},"pop",[32,1151,209],{"class":67},[32,1153,1155,1157,1159],{"class":34,"line":1154},23,[32,1156,992],{"class":67},[32,1158,677],{"class":92},[32,1160,209],{"class":67},[32,1162,1164],{"class":34,"line":1163},24,[32,1165,148],{"class":67},[32,1167,1169],{"class":34,"line":1168},25,[32,1170,58],{"emptyLinePlaceholder":57},[32,1172,1174,1177,1180,1182,1184,1186],{"class":34,"line":1173},26,[32,1175,1176],{"class":38},"    bool",[32,1178,1179],{"class":92}," try_push",[32,1181,509],{"class":67},[32,1183,961],{"class":175},[32,1185,964],{"class":929},[32,1187,132],{"class":67},[32,1189,1191,1193,1195,1197,1199,1201,1203,1205],{"class":34,"line":1190},27,[32,1192,971],{"class":175},[32,1194,974],{"class":67},[32,1196,120],{"class":38},[32,1198,317],{"class":175},[32,1200,432],{"class":67},[32,1202,435],{"class":38},[32,1204,438],{"class":92},[32,1206,987],{"class":67},[32,1208,1210,1213,1216,1218,1220,1223,1226,1228,1231],{"class":34,"line":1209},28,[32,1211,1212],{"class":38},"        if",[32,1214,1215],{"class":67}," (queue_.",[32,1217,1011],{"class":92},[32,1219,1014],{"class":67},[32,1221,1222],{"class":38},">=",[32,1224,1225],{"class":67}," capacity_) ",[32,1227,647],{"class":38},[32,1229,1230],{"class":74}," false",[32,1232,78],{"class":67},[32,1234,1236,1238,1240,1242,1244,1246,1248],{"class":34,"line":1235},29,[32,1237,1024],{"class":67},[32,1239,1027],{"class":92},[32,1241,509],{"class":67},[32,1243,317],{"class":175},[32,1245,489],{"class":67},[32,1247,1036],{"class":92},[32,1249,1039],{"class":67},[32,1251,1253,1255,1257],{"class":34,"line":1252},30,[32,1254,1044],{"class":67},[32,1256,677],{"class":92},[32,1258,209],{"class":67},[32,1260,1262,1265,1268],{"class":34,"line":1261},31,[32,1263,1264],{"class":38},"        return",[32,1266,1267],{"class":74}," true",[32,1269,78],{"class":67},[32,1271,1273],{"class":34,"line":1272},32,[32,1274,148],{"class":67},[32,1276,1278],{"class":34,"line":1277},33,[32,1279,58],{"emptyLinePlaceholder":57},[32,1281,1283,1286,1289,1291,1294],{"class":34,"line":1282},34,[32,1284,1285],{"class":38},"    size_t",[32,1287,1288],{"class":92}," size",[32,1290,1014],{"class":67},[32,1292,1293],{"class":38},"const",[32,1295,909],{"class":67},[32,1297,1299,1301,1303,1305,1307,1309,1311,1313],{"class":34,"line":1298},35,[32,1300,971],{"class":175},[32,1302,974],{"class":67},[32,1304,120],{"class":38},[32,1306,317],{"class":175},[32,1308,432],{"class":67},[32,1310,435],{"class":38},[32,1312,438],{"class":92},[32,1314,987],{"class":67},[32,1316,1318,1320,1322,1324],{"class":34,"line":1317},36,[32,1319,1264],{"class":38},[32,1321,1008],{"class":67},[32,1323,1011],{"class":92},[32,1325,209],{"class":67},[32,1327,1329],{"class":34,"line":1328},37,[32,1330,148],{"class":67},[32,1332,1334],{"class":34,"line":1333},38,[32,1335,58],{"emptyLinePlaceholder":57},[32,1337,1339],{"class":34,"line":1338},39,[32,1340,1341],{"class":38},"private:\n",[32,1343,1345,1347],{"class":34,"line":1344},40,[32,1346,1285],{"class":38},[32,1348,1349],{"class":67}," capacity_;\n",[32,1351,1353,1355,1358,1360,1362,1364],{"class":34,"line":1352},41,[32,1354,176],{"class":175},[32,1356,1357],{"class":67},"::queue",[32,1359,120],{"class":38},[32,1361,961],{"class":67},[32,1363,435],{"class":38},[32,1365,1366],{"class":67}," queue_;\n",[32,1368,1370,1373,1375,1378],{"class":34,"line":1369},42,[32,1371,1372],{"class":38},"    mutable",[32,1374,237],{"class":175},[32,1376,1377],{"class":67},"::mutex mutex_;",[32,1379,1380],{"class":338},"       \u002F\u002F mutable：const 方法里也能加锁\n",[32,1382,1384,1386],{"class":34,"line":1383},43,[32,1385,176],{"class":175},[32,1387,1388],{"class":67},"::condition_variable not_full_;\n",[32,1390,1392,1394],{"class":34,"line":1391},44,[32,1393,176],{"class":175},[32,1395,1396],{"class":67},"::condition_variable not_empty_;\n",[32,1398,1400],{"class":34,"line":1399},45,[32,1401,1402],{"class":67},"};\n",[10,1404,1405],{},[263,1406,1407],{},"几个细节：",[1409,1410,1411,1414,1420],"ul",{},[562,1412,1413],{},"两个条件变量分开（not_full \u002F not_empty）：每次只唤醒对应的等待方，避免惊群",[562,1415,1416,1419],{},[29,1417,1418],{},"mutable mutex_","：size() 是 const 方法，但读 queue_.size() 也需要加锁防止读到中间态",[562,1421,1422,1425],{},[29,1423,1424],{},"std::move","：push 时 move 进去，pop 时 move 出来，避免不必要的拷贝",[295,1427],{},[14,1429,1431],{"id":1430},"实战二线程池","实战二：线程池",[10,1433,1434],{},"线程池 = 有界阻塞队列 + 一组工作线程。",[10,1436,1437],{},[263,1438,1439],{},"类比餐厅：",[1409,1441,1442,1445,1448],{},[562,1443,1444],{},"厨师 = 线程（提前雇好，一直在岗）",[562,1446,1447],{},"点单 = 提交任务",[562,1449,1450],{},"待处理订单队列 = 任务队列",[10,1452,1453],{},"不用线程池的话，每来一个任务就 new thread，做完就销毁——每次点菜都临时招一个厨师，代价极高。",[10,1455,1456],{},[263,1457,1458],{},"结构：",[22,1460,1463],{"className":1461,"code":1462,"language":254},[252],"ThreadPool\n├── vector\u003Cthread> workers        \u002F\u002F 固定数量的工作线程\n├── queue\u003Cfunction\u003Cvoid()>> tasks \u002F\u002F 待执行的任务队列\n├── mutex                         \u002F\u002F 保护任务队列\n├── condition_variable            \u002F\u002F 通知有新任务 \u002F 要关闭了\n└── bool stop                     \u002F\u002F 析构时通知线程退出\n",[29,1464,1462],{"__ignoreMap":27},[10,1466,1467],{},[263,1468,1469],{},"完整实现：",[22,1471,1473],{"className":24,"code":1472,"language":26,"meta":27,"style":27},"#include \u003Cvector>\n#include \u003Cqueue>\n#include \u003Cthread>\n#include \u003Cmutex>\n#include \u003Ccondition_variable>\n#include \u003Cfunctional>\n#include \u003Cfuture>\n#include \u003Cstdexcept>\n\nclass ThreadPool {\npublic:\n    explicit ThreadPool(size_t n) : stop_(false) {\n        for (size_t i = 0; i \u003C n; ++i) {\n            workers_.emplace_back([this] {\n                while (true) {\n                    std::function\u003Cvoid()> task;\n                    {\n                        std::unique_lock\u003Cstd::mutex> lock(mutex_);\n                        cv_.wait(lock, [this] {\n                            return stop_ || !tasks_.empty();\n                        });\n                        if (stop_ && tasks_.empty()) return;\n                        task = std::move(tasks_.front());\n                        tasks_.pop();\n                    }\n                    task();  \u002F\u002F 锁已释放，执行任务\n                }\n            });\n        }\n    }\n\n    template\u003Ctypename F, typename... Args>\n    auto submit(F&& f, Args&&... args)\n        -> std::future\u003Cdecltype(f(args...))>\n    {\n        using ReturnType = decltype(f(args...));\n\n        \u002F\u002F packaged_task 不可拷贝，用 shared_ptr 包装后 lambda 可以捕获\n        auto task = std::make_shared\u003Cstd::packaged_task\u003CReturnType()>>(\n            std::bind(std::forward\u003CF>(f), std::forward\u003CArgs>(args)...)\n        );\n\n        std::future\u003CReturnType> result = task->get_future();\n        {\n            std::unique_lock\u003Cstd::mutex> lock(mutex_);\n            if (stop_) throw std::runtime_error(\"submit on stopped ThreadPool\");\n            tasks_.emplace([task] { (*task)(); });\n        }\n        cv_.notify_one();\n        return result;\n    }\n\n    ~ThreadPool() {\n        {\n            std::unique_lock\u003Cstd::mutex> lock(mutex_);\n            stop_ = true;\n        }\n        cv_.notify_all();  \u002F\u002F 唤醒所有线程检查 stop_\n        for (auto& w : workers_) w.join();\n    }\n\nprivate:\n    std::vector\u003Cstd::thread> workers_;\n    std::queue\u003Cstd::function\u003Cvoid()>> tasks_;\n    std::mutex mutex_;\n    std::condition_variable cv_;\n    bool stop_;\n};\n",[29,1474,1475,1482,1488,1494,1500,1506,1513,1520,1527,1531,1540,1544,1570,1597,1613,1625,1644,1649,1668,1681,1701,1706,1729,1749,1758,1763,1773,1778,1783,1788,1792,1796,1821,1852,1877,1882,1903,1907,1912,1946,1985,1990,1994,2020,2025,2043,2070,2093,2098,2108,2116,2121,2126,2134,2139,2158,2170,2175,2187,2204,2209,2214,2219,2239,2262,2270,2278,2286],{"__ignoreMap":27},[32,1476,1477,1479],{"class":34,"line":35},[32,1478,39],{"class":38},[32,1480,1481],{"class":42}," \u003Cvector>\n",[32,1483,1484,1486],{"class":34,"line":46},[32,1485,39],{"class":38},[32,1487,864],{"class":42},[32,1489,1490,1492],{"class":34,"line":54},[32,1491,39],{"class":38},[32,1493,51],{"class":42},[32,1495,1496,1498],{"class":34,"line":61},[32,1497,39],{"class":38},[32,1499,871],{"class":42},[32,1501,1502,1504],{"class":34,"line":81},[32,1503,39],{"class":38},[32,1505,878],{"class":42},[32,1507,1508,1510],{"class":34,"line":86},[32,1509,39],{"class":38},[32,1511,1512],{"class":42}," \u003Cfunctional>\n",[32,1514,1515,1517],{"class":34,"line":99},[32,1516,39],{"class":38},[32,1518,1519],{"class":42}," \u003Cfuture>\n",[32,1521,1522,1524],{"class":34,"line":135},[32,1523,39],{"class":38},[32,1525,1526],{"class":42}," \u003Cstdexcept>\n",[32,1528,1529],{"class":34,"line":145},[32,1530,58],{"emptyLinePlaceholder":57},[32,1532,1533,1535,1538],{"class":34,"line":151},[32,1534,903],{"class":38},[32,1536,1537],{"class":175}," ThreadPool",[32,1539,909],{"class":67},[32,1541,1542],{"class":34,"line":157},[32,1543,914],{"class":38},[32,1545,1546,1548,1550,1552,1554,1557,1560,1563,1565,1568],{"class":34,"line":162},[32,1547,919],{"class":38},[32,1549,1537],{"class":92},[32,1551,509],{"class":67},[32,1553,926],{"class":38},[32,1555,1556],{"class":929}," n",[32,1558,1559],{"class":67},") : ",[32,1561,1562],{"class":92},"stop_",[32,1564,509],{"class":67},[32,1566,1567],{"class":74},"false",[32,1569,132],{"class":67},[32,1571,1572,1575,1577,1579,1581,1583,1585,1587,1589,1592,1594],{"class":34,"line":172},[32,1573,1574],{"class":38},"        for",[32,1576,105],{"class":67},[32,1578,926],{"class":38},[32,1580,110],{"class":67},[32,1582,71],{"class":38},[32,1584,75],{"class":74},[32,1586,117],{"class":67},[32,1588,120],{"class":38},[32,1590,1591],{"class":67}," n; ",[32,1593,129],{"class":38},[32,1595,1596],{"class":67},"i) {\n",[32,1598,1599,1602,1605,1608,1610],{"class":34,"line":188},[32,1600,1601],{"class":67},"            workers_.",[32,1603,1604],{"class":92},"emplace_back",[32,1606,1607],{"class":67},"([",[32,1609,1000],{"class":74},[32,1611,1612],{"class":67},"] {\n",[32,1614,1615,1618,1620,1623],{"class":34,"line":200},[32,1616,1617],{"class":38},"                while",[32,1619,105],{"class":67},[32,1621,1622],{"class":74},"true",[32,1624,132],{"class":67},[32,1626,1627,1630,1633,1636,1639,1641],{"class":34,"line":212},[32,1628,1629],{"class":175},"                    std",[32,1631,1632],{"class":67},"::function",[32,1634,1635],{"class":38},"\u003Cvoid",[32,1637,1638],{"class":67},"()",[32,1640,435],{"class":38},[32,1642,1643],{"class":67}," task;\n",[32,1645,1646],{"class":34,"line":222},[32,1647,1648],{"class":67},"                    {\n",[32,1650,1651,1654,1656,1658,1660,1662,1664,1666],{"class":34,"line":243},[32,1652,1653],{"class":175},"                        std",[32,1655,974],{"class":67},[32,1657,120],{"class":38},[32,1659,317],{"class":175},[32,1661,432],{"class":67},[32,1663,435],{"class":38},[32,1665,438],{"class":92},[32,1667,987],{"class":67},[32,1669,1670,1673,1675,1677,1679],{"class":34,"line":1077},[32,1671,1672],{"class":67},"                        cv_.",[32,1674,641],{"class":92},[32,1676,997],{"class":67},[32,1678,1000],{"class":74},[32,1680,1612],{"class":67},[32,1682,1683,1686,1689,1692,1694,1697,1699],{"class":34,"line":1096},[32,1684,1685],{"class":38},"                            return",[32,1687,1688],{"class":67}," stop_ ",[32,1690,1691],{"class":38},"||",[32,1693,650],{"class":38},[32,1695,1696],{"class":67},"tasks_.",[32,1698,593],{"class":92},[32,1700,209],{"class":67},[32,1702,1703],{"class":34,"line":1121},[32,1704,1705],{"class":67},"                        });\n",[32,1707,1708,1711,1714,1717,1720,1722,1725,1727],{"class":34,"line":1144},[32,1709,1710],{"class":38},"                        if",[32,1712,1713],{"class":67}," (stop_ ",[32,1715,1716],{"class":38},"&&",[32,1718,1719],{"class":67}," tasks_.",[32,1721,593],{"class":92},[32,1723,1724],{"class":67},"()) ",[32,1726,647],{"class":38},[32,1728,78],{"class":67},[32,1730,1731,1734,1736,1738,1740,1742,1745,1747],{"class":34,"line":1154},[32,1732,1733],{"class":67},"                        task ",[32,1735,71],{"class":38},[32,1737,237],{"class":175},[32,1739,489],{"class":67},[32,1741,1036],{"class":92},[32,1743,1744],{"class":67},"(tasks_.",[32,1746,1138],{"class":92},[32,1748,1141],{"class":67},[32,1750,1751,1754,1756],{"class":34,"line":1163},[32,1752,1753],{"class":67},"                        tasks_.",[32,1755,1149],{"class":92},[32,1757,209],{"class":67},[32,1759,1760],{"class":34,"line":1168},[32,1761,1762],{"class":67},"                    }\n",[32,1764,1765,1768,1770],{"class":34,"line":1173},[32,1766,1767],{"class":92},"                    task",[32,1769,335],{"class":67},[32,1771,1772],{"class":338},"  \u002F\u002F 锁已释放，执行任务\n",[32,1774,1775],{"class":34,"line":1190},[32,1776,1777],{"class":67},"                }\n",[32,1779,1780],{"class":34,"line":1209},[32,1781,1782],{"class":67},"            });\n",[32,1784,1785],{"class":34,"line":1235},[32,1786,1787],{"class":67},"        }\n",[32,1789,1790],{"class":34,"line":1252},[32,1791,148],{"class":67},[32,1793,1794],{"class":34,"line":1261},[32,1795,58],{"emptyLinePlaceholder":57},[32,1797,1798,1801,1803,1805,1808,1811,1813,1816,1819],{"class":34,"line":1272},[32,1799,1800],{"class":38},"    template",[32,1802,120],{"class":67},[32,1804,892],{"class":38},[32,1806,1807],{"class":175}," F",[32,1809,1810],{"class":67},", ",[32,1812,892],{"class":38},[32,1814,1815],{"class":67},"... ",[32,1817,1818],{"class":175},"Args",[32,1820,898],{"class":67},[32,1822,1823,1826,1829,1831,1834,1836,1839,1841,1843,1845,1847,1850],{"class":34,"line":1277},[32,1824,1825],{"class":38},"    auto",[32,1827,1828],{"class":92}," submit",[32,1830,509],{"class":67},[32,1832,1833],{"class":175},"F",[32,1835,1716],{"class":38},[32,1837,1838],{"class":929}," f",[32,1840,1810],{"class":67},[32,1842,1818],{"class":175},[32,1844,1716],{"class":38},[32,1846,1815],{"class":67},[32,1848,1849],{"class":929},"args",[32,1851,933],{"class":67},[32,1853,1854,1857,1859,1861,1864,1866,1869,1871,1874],{"class":34,"line":1282},[32,1855,1856],{"class":67},"        -> ",[32,1858,317],{"class":175},[32,1860,489],{"class":67},[32,1862,1863],{"class":175},"future",[32,1865,120],{"class":67},[32,1867,1868],{"class":38},"decltype",[32,1870,509],{"class":67},[32,1872,1873],{"class":92},"f",[32,1875,1876],{"class":67},"(args...))>\n",[32,1878,1879],{"class":34,"line":1298},[32,1880,1881],{"class":67},"    {\n",[32,1883,1884,1887,1890,1893,1896,1898,1900],{"class":34,"line":1317},[32,1885,1886],{"class":38},"        using",[32,1888,1889],{"class":175}," ReturnType",[32,1891,1892],{"class":38}," =",[32,1894,1895],{"class":38}," decltype",[32,1897,509],{"class":67},[32,1899,1873],{"class":92},[32,1901,1902],{"class":67},"(args...));\n",[32,1904,1905],{"class":34,"line":1328},[32,1906,58],{"emptyLinePlaceholder":57},[32,1908,1909],{"class":34,"line":1333},[32,1910,1911],{"class":338},"        \u002F\u002F packaged_task 不可拷贝，用 shared_ptr 包装后 lambda 可以捕获\n",[32,1913,1914,1917,1920,1922,1924,1926,1929,1931,1933,1935,1938,1940,1943],{"class":34,"line":1338},[32,1915,1916],{"class":38},"        auto",[32,1918,1919],{"class":67}," task ",[32,1921,71],{"class":38},[32,1923,237],{"class":175},[32,1925,489],{"class":67},[32,1927,1928],{"class":92},"make_shared",[32,1930,120],{"class":67},[32,1932,317],{"class":175},[32,1934,489],{"class":67},[32,1936,1937],{"class":175},"packaged_task",[32,1939,120],{"class":67},[32,1941,1942],{"class":175},"ReturnType",[32,1944,1945],{"class":67},"()>>(\n",[32,1947,1948,1951,1953,1956,1958,1960,1962,1965,1967,1969,1972,1974,1976,1978,1980,1982],{"class":34,"line":1344},[32,1949,1950],{"class":175},"            std",[32,1952,489],{"class":67},[32,1954,1955],{"class":92},"bind",[32,1957,509],{"class":67},[32,1959,317],{"class":175},[32,1961,489],{"class":67},[32,1963,1964],{"class":92},"forward",[32,1966,120],{"class":67},[32,1968,1833],{"class":175},[32,1970,1971],{"class":67},">(f), ",[32,1973,317],{"class":175},[32,1975,489],{"class":67},[32,1977,1964],{"class":92},[32,1979,120],{"class":67},[32,1981,1818],{"class":175},[32,1983,1984],{"class":67},">(args)...)\n",[32,1986,1987],{"class":34,"line":1352},[32,1988,1989],{"class":67},"        );\n",[32,1991,1992],{"class":34,"line":1369},[32,1993,58],{"emptyLinePlaceholder":57},[32,1995,1996,1998,2001,2003,2005,2007,2010,2012,2015,2018],{"class":34,"line":1383},[32,1997,971],{"class":175},[32,1999,2000],{"class":67},"::future",[32,2002,120],{"class":38},[32,2004,1942],{"class":67},[32,2006,435],{"class":38},[32,2008,2009],{"class":67}," result ",[32,2011,71],{"class":38},[32,2013,2014],{"class":67}," task->",[32,2016,2017],{"class":92},"get_future",[32,2019,209],{"class":67},[32,2021,2022],{"class":34,"line":1391},[32,2023,2024],{"class":67},"        {\n",[32,2026,2027,2029,2031,2033,2035,2037,2039,2041],{"class":34,"line":1399},[32,2028,1950],{"class":175},[32,2030,974],{"class":67},[32,2032,120],{"class":38},[32,2034,317],{"class":175},[32,2036,432],{"class":67},[32,2038,435],{"class":38},[32,2040,438],{"class":92},[32,2042,987],{"class":67},[32,2044,2046,2049,2052,2055,2057,2059,2062,2064,2067],{"class":34,"line":2045},46,[32,2047,2048],{"class":38},"            if",[32,2050,2051],{"class":67}," (stop_) ",[32,2053,2054],{"class":38},"throw",[32,2056,237],{"class":175},[32,2058,489],{"class":67},[32,2060,2061],{"class":92},"runtime_error",[32,2063,509],{"class":67},[32,2065,2066],{"class":42},"\"submit on stopped ThreadPool\"",[32,2068,2069],{"class":67},");\n",[32,2071,2073,2076,2079,2081,2084,2087,2090],{"class":34,"line":2072},47,[32,2074,2075],{"class":67},"            tasks_.",[32,2077,2078],{"class":92},"emplace",[32,2080,1607],{"class":67},[32,2082,2083],{"class":929},"task",[32,2085,2086],{"class":67},"] { (",[32,2088,2089],{"class":38},"*",[32,2091,2092],{"class":67},"task)(); });\n",[32,2094,2096],{"class":34,"line":2095},48,[32,2097,1787],{"class":67},[32,2099,2101,2104,2106],{"class":34,"line":2100},49,[32,2102,2103],{"class":67},"        cv_.",[32,2105,677],{"class":92},[32,2107,209],{"class":67},[32,2109,2111,2113],{"class":34,"line":2110},50,[32,2112,1264],{"class":38},[32,2114,2115],{"class":67}," result;\n",[32,2117,2119],{"class":34,"line":2118},51,[32,2120,148],{"class":67},[32,2122,2124],{"class":34,"line":2123},52,[32,2125,58],{"emptyLinePlaceholder":57},[32,2127,2129,2132],{"class":34,"line":2128},53,[32,2130,2131],{"class":92},"    ~ThreadPool",[32,2133,96],{"class":67},[32,2135,2137],{"class":34,"line":2136},54,[32,2138,2024],{"class":67},[32,2140,2142,2144,2146,2148,2150,2152,2154,2156],{"class":34,"line":2141},55,[32,2143,1950],{"class":175},[32,2145,974],{"class":67},[32,2147,120],{"class":38},[32,2149,317],{"class":175},[32,2151,432],{"class":67},[32,2153,435],{"class":38},[32,2155,438],{"class":92},[32,2157,987],{"class":67},[32,2159,2161,2164,2166,2168],{"class":34,"line":2160},56,[32,2162,2163],{"class":67},"            stop_ ",[32,2165,71],{"class":38},[32,2167,1267],{"class":74},[32,2169,78],{"class":67},[32,2171,2173],{"class":34,"line":2172},57,[32,2174,1787],{"class":67},[32,2176,2178,2180,2182,2184],{"class":34,"line":2177},58,[32,2179,2103],{"class":67},[32,2181,689],{"class":92},[32,2183,335],{"class":67},[32,2185,2186],{"class":338},"  \u002F\u002F 唤醒所有线程检查 stop_\n",[32,2188,2190,2192,2194,2197,2200,2202],{"class":34,"line":2189},59,[32,2191,1574],{"class":38},[32,2193,105],{"class":67},[32,2195,2196],{"class":38},"auto&",[32,2198,2199],{"class":67}," w : workers_) w.",[32,2201,206],{"class":92},[32,2203,209],{"class":67},[32,2205,2207],{"class":34,"line":2206},60,[32,2208,148],{"class":67},[32,2210,2212],{"class":34,"line":2211},61,[32,2213,58],{"emptyLinePlaceholder":57},[32,2215,2217],{"class":34,"line":2216},62,[32,2218,1341],{"class":38},[32,2220,2222,2224,2227,2229,2231,2234,2236],{"class":34,"line":2221},63,[32,2223,176],{"class":175},[32,2225,2226],{"class":67},"::vector",[32,2228,120],{"class":38},[32,2230,317],{"class":175},[32,2232,2233],{"class":67},"::thread",[32,2235,435],{"class":38},[32,2237,2238],{"class":67}," workers_;\n",[32,2240,2242,2244,2246,2248,2250,2252,2254,2256,2259],{"class":34,"line":2241},64,[32,2243,176],{"class":175},[32,2245,1357],{"class":67},[32,2247,120],{"class":38},[32,2249,317],{"class":175},[32,2251,1632],{"class":67},[32,2253,1635],{"class":38},[32,2255,1638],{"class":67},[32,2257,2258],{"class":38},">>",[32,2260,2261],{"class":67}," tasks_;\n",[32,2263,2265,2267],{"class":34,"line":2264},65,[32,2266,176],{"class":175},[32,2268,2269],{"class":67},"::mutex mutex_;\n",[32,2271,2273,2275],{"class":34,"line":2272},66,[32,2274,176],{"class":175},[32,2276,2277],{"class":67},"::condition_variable cv_;\n",[32,2279,2281,2283],{"class":34,"line":2280},67,[32,2282,1176],{"class":38},[32,2284,2285],{"class":67}," stop_;\n",[32,2287,2289],{"class":34,"line":2288},68,[32,2290,1402],{"class":67},[10,2292,2293],{},[263,2294,2295],{},"使用：",[22,2297,2299],{"className":24,"code":2298,"language":26,"meta":27,"style":27},"ThreadPool pool(4);\n\nauto f1 = pool.submit([](int a, int b) { return a + b; }, 3, 5);\nauto f2 = pool.submit([] { return 42; });\n\nstd::cout \u003C\u003C f1.get() \u003C\u003C \"\\n\";  \u002F\u002F 8\nstd::cout \u003C\u003C f2.get() \u003C\u003C \"\\n\";  \u002F\u002F 42\n",[29,2300,2301,2316,2320,2375,2399,2403,2436],{"__ignoreMap":27},[32,2302,2303,2306,2309,2311,2314],{"class":34,"line":35},[32,2304,2305],{"class":175},"ThreadPool",[32,2307,2308],{"class":92}," pool",[32,2310,509],{"class":67},[32,2312,2313],{"class":74},"4",[32,2315,2069],{"class":67},[32,2317,2318],{"class":34,"line":46},[32,2319,58],{"emptyLinePlaceholder":57},[32,2321,2322,2325,2328,2330,2333,2336,2339,2341,2344,2346,2348,2351,2354,2356,2359,2362,2365,2368,2370,2373],{"class":34,"line":54},[32,2323,2324],{"class":38},"auto",[32,2326,2327],{"class":67}," f1 ",[32,2329,71],{"class":38},[32,2331,2332],{"class":67}," pool.",[32,2334,2335],{"class":92},"submit",[32,2337,2338],{"class":67},"([](",[32,2340,64],{"class":38},[32,2342,2343],{"class":929}," a",[32,2345,1810],{"class":67},[32,2347,64],{"class":38},[32,2349,2350],{"class":929}," b",[32,2352,2353],{"class":67},") { ",[32,2355,647],{"class":38},[32,2357,2358],{"class":67}," a ",[32,2360,2361],{"class":38},"+",[32,2363,2364],{"class":67}," b; }, ",[32,2366,2367],{"class":74},"3",[32,2369,1810],{"class":67},[32,2371,2372],{"class":74},"5",[32,2374,2069],{"class":67},[32,2376,2377,2379,2382,2384,2386,2388,2391,2393,2396],{"class":34,"line":61},[32,2378,2324],{"class":38},[32,2380,2381],{"class":67}," f2 ",[32,2383,71],{"class":38},[32,2385,2332],{"class":67},[32,2387,2335],{"class":92},[32,2389,2390],{"class":67},"([] { ",[32,2392,647],{"class":38},[32,2394,2395],{"class":74}," 42",[32,2397,2398],{"class":67},"; });\n",[32,2400,2401],{"class":34,"line":81},[32,2402,58],{"emptyLinePlaceholder":57},[32,2404,2405,2407,2409,2411,2414,2417,2419,2421,2424,2428,2431,2433],{"class":34,"line":86},[32,2406,317],{"class":175},[32,2408,227],{"class":67},[32,2410,230],{"class":38},[32,2412,2413],{"class":67}," f1.",[32,2415,2416],{"class":92},"get",[32,2418,1014],{"class":67},[32,2420,230],{"class":38},[32,2422,2423],{"class":42}," \"",[32,2425,2427],{"class":2426},"sxsTv","\\n",[32,2429,2430],{"class":42},"\"",[32,2432,349],{"class":67},[32,2434,2435],{"class":338},"  \u002F\u002F 8\n",[32,2437,2438,2440,2442,2444,2447,2449,2451,2453,2455,2457,2459,2461],{"class":34,"line":99},[32,2439,317],{"class":175},[32,2441,227],{"class":67},[32,2443,230],{"class":38},[32,2445,2446],{"class":67}," f2.",[32,2448,2416],{"class":92},[32,2450,1014],{"class":67},[32,2452,230],{"class":38},[32,2454,2423],{"class":42},[32,2456,2427],{"class":2426},[32,2458,2430],{"class":42},[32,2460,349],{"class":67},[32,2462,2463],{"class":338},"  \u002F\u002F 42\n",[10,2465,2466],{},[263,2467,2468],{},"几个关键问题：",[10,2470,2471,2474],{},[263,2472,2473],{},"为什么用 packaged_task 而不是直接存 function？","\n因为要拿返回值。packaged_task 内部绑定了一个 promise，执行完自动把结果放进去，外面用 future.get() 取出来。",[10,2476,2477,2480],{},[263,2478,2479],{},"为什么 task 要用 shared_ptr 包装？","\npackaged_task 不能拷贝，但 std::function 要求内容可拷贝。shared_ptr 本身可拷贝（引用计数），lambda 捕获 shared_ptr 后存进 function\u003Cvoid()> 就没问题了。",[10,2482,2483,2486],{},[263,2484,2485],{},"析构为什么用 notify_all 而不是 notify_one？","\n要让所有线程都醒来检查 stop_，不然没被唤醒的线程会永远阻塞，join() 就会卡死。",[10,2488,2489],{},[263,2490,2491],{},"默写路径（按逻辑推导，不要硬背）：",[22,2493,2496],{"className":2494,"code":2495,"language":254},[252],"1. 构造：for(n个线程) { emplace_back(主循环lambda) }\n2. 主循环：while(true) { 加锁→wait→取任务→解锁→执行 }\n3. wait 条件：stop_ || !tasks_.empty()\n4. 退出条件：stop_ && tasks_.empty()\n5. submit：packaged_task→shared_ptr→lambda入队→notify_one→返回future\n6. 析构：stop_=true→notify_all→join all\n",[29,2497,2495],{"__ignoreMap":27},[295,2499],{},[14,2501,2502],{"id":2502},"量化开发手撕路线图",[10,2504,2505],{},"有了并发基础，接下来的学习路径：",[10,2507,2508],{},[263,2509,2510],{},"第一阶段（并发基础，已完成）",[1409,2512,2513,2516,2519],{},[562,2514,2515],{},"✅ 数据竞争、mutex、lock_guard、unique_lock",[562,2517,2518],{},"✅ condition_variable、有界阻塞队列",[562,2520,2521],{},"✅ 线程池",[10,2523,2524],{},[263,2525,2526],{},"第二阶段（量化特色）",[1409,2528,2529,2532,2535],{},[562,2530,2531],{},"内存池：预分配 + freelist，避免 malloc 开销",[562,2533,2534],{},"SPSC 无锁队列：ring buffer + atomic，行情线程→策略线程的标准方案",[562,2536,2537],{},"读写锁：shared_mutex，读多写少场景",[10,2539,2540],{},[263,2541,2542],{},"第三阶段（数据结构）",[1409,2544,2545,2548,2551],{},[562,2546,2547],{},"LRU Cache（unordered_map + list）",[562,2549,2550],{},"滑动窗口均值\u002F方差（O(1) 更新）",[562,2552,2553],{},"定时器轮（TimerWheel）",[10,2555,2556,2557,2560],{},"量化开发和普通后端的核心差异是",[263,2558,2559],{},"低延迟意识","：每写一行代码都要问自己\"这里有没有不必要的拷贝\u002F锁\u002F内存分配\"。mutex 版本写对写熟比死磕无锁更重要，面试官更在意你理解 happens-before 和数据竞争，不在意你背了多少原子操作。",[2562,2563,2564],"style",{},"html pre.shiki code .s6PUj, html code.shiki .s6PUj{--shiki-default:#F47067;--shiki-light:#D73A49}html pre.shiki code .sXfbr, html code.shiki .sXfbr{--shiki-default:#96D0FF;--shiki-light:#032F62}html pre.shiki code .ssh_m, html code.shiki .ssh_m{--shiki-default:#ADBAC7;--shiki-light:#24292E}html pre.shiki code .swcJU, html code.shiki .swcJU{--shiki-default:#6CB6FF;--shiki-light:#005CC5}html pre.shiki code .saVmf, html code.shiki .saVmf{--shiki-default:#DCBDFB;--shiki-light:#6F42C1}html pre.shiki code .sqRhv, html code.shiki .sqRhv{--shiki-default:#F69D50;--shiki-light:#6F42C1}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 .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html pre.shiki code .sgHix, html code.shiki .sgHix{--shiki-default:#768390;--shiki-light:#6A737D}html pre.shiki code .sNjOc, html code.shiki .sNjOc{--shiki-default:#F69D50;--shiki-light:#E36209}html pre.shiki code .sxsTv, html code.shiki .sxsTv{--shiki-default:#F47067;--shiki-light:#005CC5}",{"title":27,"searchDepth":46,"depth":54,"links":2566},[2567,2568,2574,2575,2576],{"id":16,"depth":46,"text":17},{"id":299,"depth":46,"text":299,"children":2569},[2570,2571,2572,2573],{"id":303,"depth":54,"text":304},{"id":404,"depth":54,"text":405},{"id":473,"depth":54,"text":474},{"id":570,"depth":54,"text":571},{"id":806,"depth":46,"text":807},{"id":1430,"depth":46,"text":1431},{"id":2502,"depth":46,"text":2502},[2578],"技术","2026-04-15",false,"md",{},"\u002Fposts\u002Fcpp-concurrency-basics",{"title":5,"description":12},"posts\u002Fcpp-concurrency-basics",[2587,2588,2589,2590],"C++","并发","面试","量化开发","21eFvkwGYZ6Yc_LYdF0uCyz5AtVLBwCsXw_QAUsfC40",[2593,2606,2618,2624,2635,2644,2653,2663,2673,2682,2691,2702,2714,2726,2734,2744,2756,2767,2777,2785,2793,2799,2805,2808,2816,2825,2833,2839,2847,2855],{"slug":2594,"path":2595,"title":2596,"date":2597,"tags":2598,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":145},"multimodal-rag-from-scratch","\u002Fposts\u002Fmultimodal-rag-from-scratch","从零实现多模态 RAG：BM25、Dense 检索、RRF 融合、MMR 重排全部手写","2026-06-30 18:00:00",[2599,2600,2601,2602,2603,2604,2605],"RAG","多模态","AI Infra","BM25","向量检索","混合检索","实习求职",{"slug":2607,"path":2608,"title":2609,"date":2610,"tags":2611,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":157},"mini-llm-engine-deep-dive","\u002Fposts\u002Fmini-llm-engine-deep-dive","讲透 mini-llm-engine：从显存碎片到六大推理优化","2026-06-30 14:00:00",[2612,2601,2613,2614,2615,2616,2617,2605],"LLM","vLLM","PagedAttention","KV Cache","推理优化","投机解码",{"slug":2619,"path":2620,"title":2621,"date":2622,"tags":2623,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":151},"mini-llm-engine-from-scratch","\u002Fposts\u002Fmini-llm-engine-from-scratch","从零实现 LLM 推理引擎：深挖 vLLM 的六大核心优化","2026-06-30 10:00:00",[2612,2601,2613,2614,2616,2617,2605],{"slug":2625,"path":2626,"title":2627,"date":2628,"tags":2629,"description":2634,"draft":2580,"hidden":2580,"published":57,"readingTime":243},"bytedance-recommendation-architecture-intern-interview","\u002Fposts\u002Fbytedance-recommendation-architecture-intern-interview","字节推荐架构实习生 Data 面试准备：推荐系统、实时特征与高并发八股","2026-06-09",[2589,2630,2631,2632,2633],"推荐系统","后端架构","实时计算","字节跳动","面向字节跳动推荐架构团队实习岗位的八股准备清单，覆盖推荐系统链路、实时数据、特征服务、高并发后端、分布式系统与项目包装。",{"slug":2636,"path":2637,"title":2638,"date":2628,"tags":2639,"description":2643,"draft":2580,"hidden":2580,"published":57,"readingTime":162},"high-concurrency-rate-limiting-algorithms","\u002Fposts\u002Fhigh-concurrency-rate-limiting-algorithms","高并发限流算法：固定窗口、滑动窗口、漏桶与令牌桶",[2640,2641,2631,2642,2589],"高并发","限流","系统设计","面试和工程都常见的限流算法总结，讲清楚固定窗口、滑动窗口、漏桶、令牌桶、并发数限制以及分布式限流如何落地。",{"slug":2645,"path":2646,"title":2647,"date":2628,"tags":2648,"description":2652,"draft":2580,"hidden":2580,"published":57,"readingTime":135},"kafka-producer-broker-consumer","\u002Fposts\u002Fkafka-producer-broker-consumer","Kafka 入门：生产者、Broker、消费者和“消费”到底是什么意思",[2649,2650,2651,2589,2630],"Kafka","消息队列","后端","用推荐系统里的用户行为日志为例，讲清楚 Kafka 的作用、Producer、Broker、Consumer、Topic、Partition、Offset 和消费语义。",{"slug":2654,"path":2655,"title":2656,"date":2628,"tags":2657,"description":2662,"draft":2580,"hidden":2580,"published":57,"readingTime":86},"leetcode-lru-merge-k-reverse-list","\u002Fposts\u002Fleetcode-lru-merge-k-reverse-list","链表与缓存高频题：LRU Cache、合并 K 个有序链表、反转链表",[2658,2659,2660,2661,2589],"算法","链表","LRU","LeetCode","面试高频算法题速记，整理 LRU Cache、合并 K 个有序链表、反转链表的核心思路、复杂度和 C++ 代码。",{"slug":2664,"path":2665,"title":2666,"date":2667,"tags":2668,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":212},"meddococr-interpreter-source-analysis","\u002Fposts\u002Fmeddococr-interpreter-source-analysis","MedDocOCR-Interpreter 源码导读：医疗文档 OCR、结构化抽取与报告解读原型","2026-05-22 10:30:00",[2669,2600,2670,2599,2671,2672],"OCR","医疗 AI","Python","源码分析",{"slug":2674,"path":2675,"title":2676,"date":2677,"tags":2678,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":151},"cet6-writing-model-essays","\u002Fposts\u002Fcet6-writing-model-essays","六级写作范文背诵包：10 个高频话题","2026-05-20 09:00:00",[2679,2680,2681],"English","CET6","Writing",{"slug":2683,"path":2684,"title":2685,"date":2686,"tags":2687,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":1190},"claude-code-context-management","\u002Fposts\u002Fclaude-code-context-management","Claude Code 上下文管理机制：从 Microcompact 到 Auto Compact","2026-05-19 10:00:00",[2688,2689,2612,2601,2690],"Claude Code","Agent","上下文工程",{"slug":2692,"path":2693,"title":2694,"date":2695,"tags":2696,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":1077},"nanotron-llm-pretraining-framework-analysis","\u002Fposts\u002Fnanotron-llm-pretraining-framework-analysis","Nanotron 项目详解：Hugging Face 的大模型预训练框架怎么做分布式训练","2026-05-10 12:10:00",[2612,2697,2698,2699,2700,2601,2701],"大模型训练","分布式训练","Nanotron","Hugging Face","PyTorch",{"slug":2703,"path":2704,"title":2705,"date":2706,"tags":2707,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":1168},"gofoundry-go-backend-foundation-framework","\u002Fposts\u002Fgofoundry-go-backend-foundation-framework","GoFoundry 项目详解：基于 Go 的后端基础框架套件设计","2026-05-10 11:20:00",[2708,2709,2710,2711,2712,2650,2713],"Go","后端框架","ORM","分布式缓存","分布式锁","项目架构",{"slug":2715,"path":2716,"title":2717,"date":2718,"tags":2719,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":1190},"cloudvault-go-cloud-storage-system","\u002Fposts\u002Fcloudvault-go-cloud-storage-system","CloudVault 项目详解：基于 Go 的云端存储与网盘系统架构设计","2026-05-10 10:30:00",[2708,2720,2721,2722,2713,2723,2724,2725],"云存储","网盘系统","分布式系统","Redis","RabbitMQ","Elasticsearch",{"slug":2727,"path":2728,"title":2729,"date":2730,"tags":2731,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":1096},"openclaw-source-code-analysis","\u002Fposts\u002Fopenclaw-source-code-analysis","OpenClaw 源码导读：个人 AI 助手的网关、通道、插件与运行时架构","2026-05-08 16:30:00",[2732,2689,2601,2733,2672],"OpenClaw","TypeScript",{"slug":2735,"path":2736,"title":2737,"date":2738,"tags":2739,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":151},"flow-matching-generative-models","\u002Fposts\u002Fflow-matching-generative-models","Flow Matching：从噪声到数据的连续流生成模型","2026-05-07 00:00:00",[2740,2741,2742,2743],"生成模型","Diffusion","Flow Matching","深度学习",{"slug":2745,"path":2746,"title":2747,"date":2748,"tags":2749,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":200},"database-ai-week4","\u002Fposts\u002Fdatabase-ai-week4","Week 4：数据库速成——从 Storage、Index、Query Optimization 到 Vector DB 与 RAG","2026-05-05 12:00:00",[2750,2751,2752,2599,2753,2754,2755],"数据库","CMU 15-445","Vector DB","LLM Memory","Query Optimization","Caching",{"slug":2757,"path":2758,"title":2759,"date":2760,"tags":2761,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":212},"distributed-systems-week3","\u002Fposts\u002Fdistributed-systems-week3","Week 3：分布式系统速成——MapReduce、Raft、容错与 Distributed KV Store","2026-05-05 11:00:00",[2722,2762,2763,2764,2765,2766,2689],"MIT 6.824","MapReduce","Raft","KV Store","Ray",{"slug":2768,"path":2769,"title":2770,"date":2771,"tags":2772,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":200},"gpu-inference-acceleration-week2","\u002Fposts\u002Fgpu-inference-acceleration-week2","Week 2：GPU 与推理加速——从 Kernel、算子融合到 LLM Serving","2026-05-05 10:00:00",[2743,2773,2774,2612,2775,2613,2776],"GPU","推理加速","CMU 10-414","TensorRT",{"slug":2778,"path":2779,"title":2780,"date":2781,"tags":2782,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":243},"dl-framework-autograd-mini","\u002Fposts\u002Fdl-framework-autograd-mini","Week 1：DL 框架与 Autograd——从计算图、反向传播到 Mini Autograd 实现","2026-05-05 09:00:00",[2743,2783,2701,2775,2784],"Autograd","Mini Framework",{"slug":2786,"path":2787,"title":2788,"date":2789,"tags":2790,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":162},"lock-free-concurrency-notes","\u002Fposts\u002Flock-free-concurrency-notes","无锁并发入门：从 CAS 到 Atomic Ring Buffer","2026-04-25",[2587,2588,2791,2792,2590],"无锁编程","性能优化",{"slug":2794,"path":2795,"title":2796,"date":2797,"tags":2798,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":81},"agent-memory","\u002Fposts\u002Fagent-memory","Agent 对话记忆化：从原理到实现","2026-04-24",[2612,2689,2599,2589],{"slug":2800,"path":2801,"title":2802,"date":2797,"tags":2803,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":86},"llm-context-compression","\u002Fposts\u002Fllm-context-compression","LLM 上下文五层压缩机制详解",[2612,2689,2804,2589],"上下文压缩",{"slug":2806,"path":2583,"title":5,"date":2579,"tags":2807,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":145},"cpp-concurrency-basics",[2587,2588,2589,2590],{"slug":2809,"path":2810,"title":2811,"date":2812,"tags":2813,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":35},"travel-in-shenzhen","\u002Fposts\u002Ftravel-in-shenzhen","XCPC 深圳游记","2026-04-13",[2814,2587,2815],"XCPC","比赛",{"slug":2817,"path":2818,"title":2819,"date":2820,"tags":2821,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":99},"backend-stack-deep-dive","\u002Fposts\u002Fbackend-stack-deep-dive","后端五件套：FastAPI \u002F Node.js \u002F SQLAlchemy async \u002F PostgreSQL \u002F Docker 面试速通","2026-04-07",[2651,2822,2823,2824,2589],"FastAPI","PostgreSQL","Docker",{"slug":2826,"path":2827,"title":2828,"date":2829,"tags":2830,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":86},"deepscientist-tech-stack","\u002Fposts\u002Fdeepscientist-tech-stack","DeepScientist 技术栈全解析：一个 AI 科研平台的架构设计","2026-04-06",[2831,2822,2832,2823,2589],"全栈","Next.js",{"slug":2834,"path":2835,"title":2836,"date":2829,"tags":2837,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":135},"minicode-source-analysis","\u002Fposts\u002Fminicode-source-analysis","MiniCode 源码解析：用 5000 行 TypeScript 实现一个 AI 编程助手",[2733,2838,2612,2672,2589],"CLI",{"slug":2840,"path":2841,"title":2842,"date":2829,"tags":2843,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":81},"nova-theme-implementation","\u002Fposts\u002Fnova-theme-implementation","我是怎么从零实现 Nova 主题的",[2844,2845,2846],"Hexo","前端","开源",{"slug":2848,"path":2849,"title":2850,"date":2851,"tags":2852,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":46},"git-cheatsheet","\u002Fposts\u002Fgit-cheatsheet","Git 常用操作备忘","2026-04-05 14:00:00",[2853,2854],"Git","工具",{"slug":2856,"path":2857,"title":2858,"date":2859,"tags":2860,"description":27,"draft":2580,"hidden":2580,"published":57,"readingTime":54},"github-actions-intro","\u002Fposts\u002Fgithub-actions-intro","GitHub Actions 入门：自动化你的工作流","2026-04-04 09:00:00",[2861,2862,2863],"GitHub Actions","CI\u002FCD","自动化",1782796011453]