[{"data":1,"prerenderedAt":2309},["ShallowReactive",2],{"post-cplusplus-concurrency":3,"home":2287},{"id":4,"title":5,"body":6,"date":2276,"description":2277,"extension":2278,"meta":2279,"navigation":168,"path":2280,"seo":2281,"stem":2282,"tags":2283,"__hash__":2286},"blog\u002Fblog\u002Fcplusplus-concurrency.md","C++并发",{"type":7,"value":8,"toc":2259},"minimark",[9,13,31,35,116,121,124,128,133,150,154,185,188,191,314,317,346,350,358,372,375,402,406,412,426,429,672,676,684,708,711,714,719,780,791,794,877,880,899,966,976,985,988,998,1015,1018,1021,1030,1109,1126,1172,1175,1181,1185,1202,1222,1233,1267,1272,1292,1296,1303,1332,1335,1379,1383,1386,1441,1445,1452,1471,1485,1499,1502,1506,1528,1532,1599,1602,1605,1619,1626,1630,1635,1644,1731,1735,1747,1777,1785,1795,1805,1810,1842,1855,1870,1874,1884,1913,1917,1920,1953,1958,1974,1977,1980,1988,1991,2097,2100,2105,2113,2129,2132,2135,2138,2151,2158,2164,2216,2222,2225,2230,2233,2238,2241,2246,2249,2255],[10,11,12],"p",{},"参考自《C++ Concurrency In Action》",[14,15,16,20],"ul",{},[17,18,19],"li",{},"作者：Anthony Williams",[17,21,22,23],{},"译者：",[24,25,30],"a",{"href":26,"rel":27,"title":29},"https:\u002F\u002Fgithub.com\u002FxiaoweiChen",[28],"nofollow","github","xiaoweiChen",[32,33,34],"h2",{"id":34},"线程管理",[14,36,37,88,102,113],{},[17,38,39,40],{},"启动新线程",[41,42,47],"pre",{"className":43,"code":44,"language":45,"meta":46,"style":46},"language-cpp shiki shiki-themes github-light github-dark","void Func1();\nvoid Func2(int);\nvoid Foo::Func3(int);\nstd::thread t1(Func1);\nstd::thread t2(Func1, 0);\nstd::thread t3(Func1, &Foo{}, 0);\n","cpp","",[48,49,50,58,64,70,76,82],"code",{"__ignoreMap":46},[51,52,55],"span",{"class":53,"line":54},"line",1,[51,56,57],{},"void Func1();\n",[51,59,61],{"class":53,"line":60},2,[51,62,63],{},"void Func2(int);\n",[51,65,67],{"class":53,"line":66},3,[51,68,69],{},"void Foo::Func3(int);\n",[51,71,73],{"class":53,"line":72},4,[51,74,75],{},"std::thread t1(Func1);\n",[51,77,79],{"class":53,"line":78},5,[51,80,81],{},"std::thread t2(Func1, 0);\n",[51,83,85],{"class":53,"line":84},6,[51,86,87],{},"std::thread t3(Func1, &Foo{}, 0);\n",[17,89,90,91],{},"等待与分离",[14,92,93,96,99],{},[17,94,95],{},"obj.join()",[17,97,98],{},"obj.detach()",[17,100,101],{},"obj.joinable()",[17,103,104,105],{},"唯一标识符",[14,106,107,110],{},[17,108,109],{},"obj.get_id()",[17,111,112],{},"std::this_thread::get_id()",[17,114,115],{},"其他",[10,117,118],{},[48,119,120],{},"std::thread::hardware_concurrency()",[32,122,123],{"id":123},"共享数据",[125,126,127],"h3",{"id":127},"使用互斥保护数据",[129,130,132],"h4",{"id":131},"stdmutex","std::mutex",[14,134,135,140,145],{},[17,136,137],{},[48,138,139],{},"lock()",[17,141,142],{},[48,143,144],{},"try_lock()",[17,146,147],{},[48,148,149],{},"unlock()",[151,152,153],"h5",{"id":153},"基本用法",[41,155,157],{"className":43,"code":156,"language":45,"meta":46,"style":46},"std::mutex m;\n\nm.lock();\n...\nm.unlock();\n",[48,158,159,164,170,175,180],{"__ignoreMap":46},[51,160,161],{"class":53,"line":54},[51,162,163],{},"std::mutex m;\n",[51,165,166],{"class":53,"line":60},[51,167,169],{"emptyLinePlaceholder":168},true,"\n",[51,171,172],{"class":53,"line":66},[51,173,174],{},"m.lock();\n",[51,176,177],{"class":53,"line":72},[51,178,179],{},"...\n",[51,181,182],{"class":53,"line":78},[51,183,184],{},"m.unlock();\n",[151,186,187],{"id":187},"避免死锁",[10,189,190],{},"多个互斥量锁住时，在所有地方应该以相同的顺序上锁，否则可能会造成死锁",[41,192,194],{"className":43,"code":193,"language":45,"meta":46,"style":46},"std::mutex m1;\nstd::mutex m2;\n\nvoid Func1()\n{\n  m1.lock();\n  m2.lock();\n  ...\n  m2.unlock();\n  m1.unlock();\n}\nvoid Func2()\n{\n  m2.lock();\n  m1.lock();\n  \u002F\u002F 应该和Func1顺序相同\n  \u002F\u002F m1.lock();\n  \u002F\u002F m2.lock();\n  ...\n  m1.unlock();\n  m2.unlock();\n}\n",[48,195,196,201,206,210,215,220,225,231,237,243,249,255,261,266,271,276,282,288,294,299,304,309],{"__ignoreMap":46},[51,197,198],{"class":53,"line":54},[51,199,200],{},"std::mutex m1;\n",[51,202,203],{"class":53,"line":60},[51,204,205],{},"std::mutex m2;\n",[51,207,208],{"class":53,"line":66},[51,209,169],{"emptyLinePlaceholder":168},[51,211,212],{"class":53,"line":72},[51,213,214],{},"void Func1()\n",[51,216,217],{"class":53,"line":78},[51,218,219],{},"{\n",[51,221,222],{"class":53,"line":84},[51,223,224],{},"  m1.lock();\n",[51,226,228],{"class":53,"line":227},7,[51,229,230],{},"  m2.lock();\n",[51,232,234],{"class":53,"line":233},8,[51,235,236],{},"  ...\n",[51,238,240],{"class":53,"line":239},9,[51,241,242],{},"  m2.unlock();\n",[51,244,246],{"class":53,"line":245},10,[51,247,248],{},"  m1.unlock();\n",[51,250,252],{"class":53,"line":251},11,[51,253,254],{},"}\n",[51,256,258],{"class":53,"line":257},12,[51,259,260],{},"void Func2()\n",[51,262,264],{"class":53,"line":263},13,[51,265,219],{},[51,267,269],{"class":53,"line":268},14,[51,270,230],{},[51,272,274],{"class":53,"line":273},15,[51,275,224],{},[51,277,279],{"class":53,"line":278},16,[51,280,281],{},"  \u002F\u002F 应该和Func1顺序相同\n",[51,283,285],{"class":53,"line":284},17,[51,286,287],{},"  \u002F\u002F m1.lock();\n",[51,289,291],{"class":53,"line":290},18,[51,292,293],{},"  \u002F\u002F m2.lock();\n",[51,295,297],{"class":53,"line":296},19,[51,298,236],{},[51,300,302],{"class":53,"line":301},20,[51,303,248],{},[51,305,307],{"class":53,"line":306},21,[51,308,242],{},[51,310,312],{"class":53,"line":311},22,[51,313,254],{},[10,315,316],{},"或者一次锁住多个互斥量",[41,318,320],{"className":43,"code":319,"language":45,"meta":46,"style":46},"std::mutex m1, m2;\nstd::lock(m1, m2);\n...\nm1.unlock();\nm2.unlock();\n",[48,321,322,327,332,336,341],{"__ignoreMap":46},[51,323,324],{"class":53,"line":54},[51,325,326],{},"std::mutex m1, m2;\n",[51,328,329],{"class":53,"line":60},[51,330,331],{},"std::lock(m1, m2);\n",[51,333,334],{"class":53,"line":66},[51,335,179],{},[51,337,338],{"class":53,"line":72},[51,339,340],{},"m1.unlock();\n",[51,342,343],{"class":53,"line":78},[51,344,345],{},"m2.unlock();\n",[129,347,349],{"id":348},"stdlock_guard","std::lock_guard\u003C>",[10,351,352,353,355,356],{},"互斥量的RAII模板类，不用手动",[48,354,139],{},"与",[48,357,149],{},[41,359,361],{"className":43,"code":360,"language":45,"meta":46,"style":46},"std::mutex m;\nstd::lock_guard\u003Cstd::mutex> lg(m);\n",[48,362,363,367],{"__ignoreMap":46},[51,364,365],{"class":53,"line":54},[51,366,163],{},[51,368,369],{"class":53,"line":60},[51,370,371],{},"std::lock_guard\u003Cstd::mutex> lg(m);\n",[10,373,374],{},"同时，可以获取并接管锁",[41,376,378],{"className":43,"code":377,"language":45,"meta":46,"style":46},"std::mutex m1, m2;\nstd::lock(m1, m2);\n\nstd::lock_guard\u003Cstd::mutex> lg1(m1, std::adopt_lock);\nstd::lock_guard\u003Cstd::mutex> lg2(m2, std::adopt_lock);\n",[48,379,380,384,388,392,397],{"__ignoreMap":46},[51,381,382],{"class":53,"line":54},[51,383,326],{},[51,385,386],{"class":53,"line":60},[51,387,331],{},[51,389,390],{"class":53,"line":66},[51,391,169],{"emptyLinePlaceholder":168},[51,393,394],{"class":53,"line":72},[51,395,396],{},"std::lock_guard\u003Cstd::mutex> lg1(m1, std::adopt_lock);\n",[51,398,399],{"class":53,"line":78},[51,400,401],{},"std::lock_guard\u003Cstd::mutex> lg2(m2, std::adopt_lock);\n",[129,403,405],{"id":404},"stdscoped_lock","std::scoped_lock\u003C>",[10,407,408,409,411],{},"C++17中的新的RAII模板，与",[48,410,349],{},"相同，不过可以接受多个互斥量，对其上锁",[41,413,415],{"className":43,"code":414,"language":45,"meta":46,"style":46},"std::mutex m1, m2;\nstd::scoped_lock\u003Cstd::mutex> sl(m1, m2);\n",[48,416,417,421],{"__ignoreMap":46},[51,418,419],{"class":53,"line":54},[51,420,326],{},[51,422,423],{"class":53,"line":60},[51,424,425],{},"std::scoped_lock\u003Cstd::mutex> sl(m1, m2);\n",[129,427,428],{"id":428},"层级锁的实现",[41,430,432],{"className":43,"code":431,"language":45,"meta":46,"style":46},"#include \u003Cclimits>\n#include \u003Cmutex>\n#include \u003Cstdexcept>\n\nclass hierarchical_mutex {\npublic:\n  hierarchical_mutex(unsigned long value)\n      : hierarchy_value(value), previous_hierarchy_value(0) {}\n  void lock() {\n    check_hieratchy(); \u002F\u002F 当前互斥量的层级与当前线程的层级相比较\n    internal_mutex.lock();\n    update_hierarchy(); \u002F\u002F 将线程层级与当前层级同步\n  }\n  void unlock() {\n    if (this_hierarchy_value != hierarchy_value)\n      throw std::logic_error(\"mutex hierarchy violated\");\n    this_hierarchy_value = previous_hierarchy_value;\n    internal_mutex.unlock();\n  }\n  bool try_lock() {\n    check_hieratchy();\n    if (!internal_mutex.try_lock())\n      return false;\n    update_hierarchy();\n    return true;\n  }\n\nprivate:\n  void check_hieratchy() {\n    if (hierarchy_value >= this_hierarchy_value)\n      throw std::logic_error(\"mutex hierarchy violated\");\n  }\n  void update_hierarchy() {\n    previous_hierarchy_value = this_hierarchy_value;\n    this_hierarchy_value = hierarchy_value;\n  }\n\nprivate:\n  std::mutex internal_mutex;\n  const unsigned long hierarchy_value;    \u002F\u002F 当前锁的层级\n  unsigned long previous_hierarchy_value; \u002F\u002F 当前锁的上一层的层级\n  static thread_local unsigned long this_hierarchy_value; \u002F\u002F 线程的层级\n};\n\nthread_local unsigned long hierarchical_mutex::this_hierarchy_value{ULONG_MAX};\n",[48,433,434,439,444,449,453,458,463,468,473,478,483,488,493,498,503,508,513,518,523,527,532,537,542,548,554,560,565,570,576,582,588,593,598,604,610,616,621,626,631,637,643,649,655,661,666],{"__ignoreMap":46},[51,435,436],{"class":53,"line":54},[51,437,438],{},"#include \u003Cclimits>\n",[51,440,441],{"class":53,"line":60},[51,442,443],{},"#include \u003Cmutex>\n",[51,445,446],{"class":53,"line":66},[51,447,448],{},"#include \u003Cstdexcept>\n",[51,450,451],{"class":53,"line":72},[51,452,169],{"emptyLinePlaceholder":168},[51,454,455],{"class":53,"line":78},[51,456,457],{},"class hierarchical_mutex {\n",[51,459,460],{"class":53,"line":84},[51,461,462],{},"public:\n",[51,464,465],{"class":53,"line":227},[51,466,467],{},"  hierarchical_mutex(unsigned long value)\n",[51,469,470],{"class":53,"line":233},[51,471,472],{},"      : hierarchy_value(value), previous_hierarchy_value(0) {}\n",[51,474,475],{"class":53,"line":239},[51,476,477],{},"  void lock() {\n",[51,479,480],{"class":53,"line":245},[51,481,482],{},"    check_hieratchy(); \u002F\u002F 当前互斥量的层级与当前线程的层级相比较\n",[51,484,485],{"class":53,"line":251},[51,486,487],{},"    internal_mutex.lock();\n",[51,489,490],{"class":53,"line":257},[51,491,492],{},"    update_hierarchy(); \u002F\u002F 将线程层级与当前层级同步\n",[51,494,495],{"class":53,"line":263},[51,496,497],{},"  }\n",[51,499,500],{"class":53,"line":268},[51,501,502],{},"  void unlock() {\n",[51,504,505],{"class":53,"line":273},[51,506,507],{},"    if (this_hierarchy_value != hierarchy_value)\n",[51,509,510],{"class":53,"line":278},[51,511,512],{},"      throw std::logic_error(\"mutex hierarchy violated\");\n",[51,514,515],{"class":53,"line":284},[51,516,517],{},"    this_hierarchy_value = previous_hierarchy_value;\n",[51,519,520],{"class":53,"line":290},[51,521,522],{},"    internal_mutex.unlock();\n",[51,524,525],{"class":53,"line":296},[51,526,497],{},[51,528,529],{"class":53,"line":301},[51,530,531],{},"  bool try_lock() {\n",[51,533,534],{"class":53,"line":306},[51,535,536],{},"    check_hieratchy();\n",[51,538,539],{"class":53,"line":311},[51,540,541],{},"    if (!internal_mutex.try_lock())\n",[51,543,545],{"class":53,"line":544},23,[51,546,547],{},"      return false;\n",[51,549,551],{"class":53,"line":550},24,[51,552,553],{},"    update_hierarchy();\n",[51,555,557],{"class":53,"line":556},25,[51,558,559],{},"    return true;\n",[51,561,563],{"class":53,"line":562},26,[51,564,497],{},[51,566,568],{"class":53,"line":567},27,[51,569,169],{"emptyLinePlaceholder":168},[51,571,573],{"class":53,"line":572},28,[51,574,575],{},"private:\n",[51,577,579],{"class":53,"line":578},29,[51,580,581],{},"  void check_hieratchy() {\n",[51,583,585],{"class":53,"line":584},30,[51,586,587],{},"    if (hierarchy_value >= this_hierarchy_value)\n",[51,589,591],{"class":53,"line":590},31,[51,592,512],{},[51,594,596],{"class":53,"line":595},32,[51,597,497],{},[51,599,601],{"class":53,"line":600},33,[51,602,603],{},"  void update_hierarchy() {\n",[51,605,607],{"class":53,"line":606},34,[51,608,609],{},"    previous_hierarchy_value = this_hierarchy_value;\n",[51,611,613],{"class":53,"line":612},35,[51,614,615],{},"    this_hierarchy_value = hierarchy_value;\n",[51,617,619],{"class":53,"line":618},36,[51,620,497],{},[51,622,624],{"class":53,"line":623},37,[51,625,169],{"emptyLinePlaceholder":168},[51,627,629],{"class":53,"line":628},38,[51,630,575],{},[51,632,634],{"class":53,"line":633},39,[51,635,636],{},"  std::mutex internal_mutex;\n",[51,638,640],{"class":53,"line":639},40,[51,641,642],{},"  const unsigned long hierarchy_value;    \u002F\u002F 当前锁的层级\n",[51,644,646],{"class":53,"line":645},41,[51,647,648],{},"  unsigned long previous_hierarchy_value; \u002F\u002F 当前锁的上一层的层级\n",[51,650,652],{"class":53,"line":651},42,[51,653,654],{},"  static thread_local unsigned long this_hierarchy_value; \u002F\u002F 线程的层级\n",[51,656,658],{"class":53,"line":657},43,[51,659,660],{},"};\n",[51,662,664],{"class":53,"line":663},44,[51,665,169],{"emptyLinePlaceholder":168},[51,667,669],{"class":53,"line":668},45,[51,670,671],{},"thread_local unsigned long hierarchical_mutex::this_hierarchy_value{ULONG_MAX};\n",[129,673,675],{"id":674},"stdunique_lock","std::unique_lock\u003C>",[10,677,355,678,680,681,683],{},[48,679,349],{},"相似，不过前者只提供了析构接口，但",[48,682,675],{},"可手动上锁，解锁更为灵活",[41,685,687],{"className":43,"code":686,"language":45,"meta":46,"style":46},"std::mutex m1, m2;\nstd::unique_lock\u003Cstd::mutex> ul1(m1, std::defer_lock); \u002F\u002F std::defer_lock表示，不对mutex上锁\nstd::unique_lock\u003Cstd::mutex> ul2(m2) \u002F\u002F m2已自动上锁\nul1.lock(); \u002F\u002F 手动上锁\n",[48,688,689,693,698,703],{"__ignoreMap":46},[51,690,691],{"class":53,"line":54},[51,692,326],{},[51,694,695],{"class":53,"line":60},[51,696,697],{},"std::unique_lock\u003Cstd::mutex> ul1(m1, std::defer_lock); \u002F\u002F std::defer_lock表示，不对mutex上锁\n",[51,699,700],{"class":53,"line":66},[51,701,702],{},"std::unique_lock\u003Cstd::mutex> ul2(m2) \u002F\u002F m2已自动上锁\n",[51,704,705],{"class":53,"line":72},[51,706,707],{},"ul1.lock(); \u002F\u002F 手动上锁\n",[125,709,710],{"id":710},"保护数据的替代方案",[129,712,713],{"id":713},"保护共享数据的初始化过程",[14,715,716],{},[17,717,718],{},"使用互斥量",[41,720,722],{"className":43,"code":721,"language":45,"meta":46,"style":46},"std::mutex m;\nstd::shared_ptr\u003CWidget> sp;\nvoid Foo()\n{\n  std::unique_lock\u003Cstd::mutex> ul(m);\n  if(!sp)\n  {\n    sp.reset(new Widget);\n  }\n  ul.unlock();\n  sp->do_something();\n}\n",[48,723,724,728,733,738,742,747,752,757,762,766,771,776],{"__ignoreMap":46},[51,725,726],{"class":53,"line":54},[51,727,163],{},[51,729,730],{"class":53,"line":60},[51,731,732],{},"std::shared_ptr\u003CWidget> sp;\n",[51,734,735],{"class":53,"line":66},[51,736,737],{},"void Foo()\n",[51,739,740],{"class":53,"line":72},[51,741,219],{},[51,743,744],{"class":53,"line":78},[51,745,746],{},"  std::unique_lock\u003Cstd::mutex> ul(m);\n",[51,748,749],{"class":53,"line":84},[51,750,751],{},"  if(!sp)\n",[51,753,754],{"class":53,"line":227},[51,755,756],{},"  {\n",[51,758,759],{"class":53,"line":233},[51,760,761],{},"    sp.reset(new Widget);\n",[51,763,764],{"class":53,"line":239},[51,765,497],{},[51,767,768],{"class":53,"line":245},[51,769,770],{},"  ul.unlock();\n",[51,772,773],{"class":53,"line":251},[51,774,775],{},"  sp->do_something();\n",[51,777,778],{"class":53,"line":257},[51,779,254],{},[14,781,782],{},[17,783,784,787,788],{},[48,785,786],{},"std::once_flag","和",[48,789,790],{},"std::call_once",[10,792,793],{},"比用互斥量消耗的资源更少",[41,795,797],{"className":43,"code":796,"language":45,"meta":46,"style":46},"std::shared_ptr\u003CWidget> sp;\nstd::once_flag flag;\nvoid Init()\n{\n  sp.reset(new Widget);\n}\nvoid Foo\n{\n  std::call_once(flag, Init);\n  sp->do_something();\n}\n\n\u002F\u002F Init()只调用了一次\nstd::thread t1(Foo);\nstd::thread t2(Foo);\nt1.join();\nt2.join();\n",[48,798,799,803,808,813,817,822,826,831,835,840,844,848,852,857,862,867,872],{"__ignoreMap":46},[51,800,801],{"class":53,"line":54},[51,802,732],{},[51,804,805],{"class":53,"line":60},[51,806,807],{},"std::once_flag flag;\n",[51,809,810],{"class":53,"line":66},[51,811,812],{},"void Init()\n",[51,814,815],{"class":53,"line":72},[51,816,219],{},[51,818,819],{"class":53,"line":78},[51,820,821],{},"  sp.reset(new Widget);\n",[51,823,824],{"class":53,"line":84},[51,825,254],{},[51,827,828],{"class":53,"line":227},[51,829,830],{},"void Foo\n",[51,832,833],{"class":53,"line":233},[51,834,219],{},[51,836,837],{"class":53,"line":239},[51,838,839],{},"  std::call_once(flag, Init);\n",[51,841,842],{"class":53,"line":245},[51,843,775],{},[51,845,846],{"class":53,"line":251},[51,847,254],{},[51,849,850],{"class":53,"line":257},[51,851,169],{"emptyLinePlaceholder":168},[51,853,854],{"class":53,"line":263},[51,855,856],{},"\u002F\u002F Init()只调用了一次\n",[51,858,859],{"class":53,"line":268},[51,860,861],{},"std::thread t1(Foo);\n",[51,863,864],{"class":53,"line":273},[51,865,866],{},"std::thread t2(Foo);\n",[51,868,869],{"class":53,"line":278},[51,870,871],{},"t1.join();\n",[51,873,874],{"class":53,"line":284},[51,875,876],{},"t2.join();\n",[129,878,879],{"id":879},"保护不常更新的数据结构",[10,881,882,883,787,886,889,890,892,893,895,896,898],{},"C++17提供",[48,884,885],{},"std::shared_mutex",[48,887,888],{},"std::shared_timed_mutex","，C++14只提供",[48,891,888],{},",\n而C++11并未提供。",[48,894,888],{},"更多操作方式，",[48,897,885],{},"有更高的性能",[41,900,902],{"className":43,"code":901,"language":45,"meta":46,"style":46},"std::shared_mutex sm;\n\nvoid Foo()\n{\n  \u002F\u002F 其他线程加锁时，不会阻塞\n  std::shared_lock\u003Cstd::shared_mutex> sl(sm);\n  ...\n}\nvoid Foo2()\n{\n  \u002F\u002F 其他线程尝试加锁时，会阻塞\n  std::lock_guard\u003Cstd::shared_mutex> lg(sm);\n  ...\n}\n",[48,903,904,909,913,917,921,926,931,935,939,944,948,953,958,962],{"__ignoreMap":46},[51,905,906],{"class":53,"line":54},[51,907,908],{},"std::shared_mutex sm;\n",[51,910,911],{"class":53,"line":60},[51,912,169],{"emptyLinePlaceholder":168},[51,914,915],{"class":53,"line":66},[51,916,737],{},[51,918,919],{"class":53,"line":72},[51,920,219],{},[51,922,923],{"class":53,"line":78},[51,924,925],{},"  \u002F\u002F 其他线程加锁时，不会阻塞\n",[51,927,928],{"class":53,"line":84},[51,929,930],{},"  std::shared_lock\u003Cstd::shared_mutex> sl(sm);\n",[51,932,933],{"class":53,"line":227},[51,934,236],{},[51,936,937],{"class":53,"line":233},[51,938,254],{},[51,940,941],{"class":53,"line":239},[51,942,943],{},"void Foo2()\n",[51,945,946],{"class":53,"line":245},[51,947,219],{},[51,949,950],{"class":53,"line":251},[51,951,952],{},"  \u002F\u002F 其他线程尝试加锁时，会阻塞\n",[51,954,955],{"class":53,"line":257},[51,956,957],{},"  std::lock_guard\u003Cstd::shared_mutex> lg(sm);\n",[51,959,960],{"class":53,"line":263},[51,961,236],{},[51,963,964],{"class":53,"line":268},[51,965,254],{},[10,967,968,969,972,973,975],{},"并行访问数据时，使用",[48,970,971],{},"std::shared_lock\u003C>","上锁，所有线程都可对数据进行访问，而修改数据时，\n使用",[48,974,349],{},"上锁，只有一个线程可以进行修改",[10,977,978,979,981,982,984],{},"限制：当有线程有共享锁(",[48,980,971],{},"上锁)时，独占锁(",[48,983,349],{},")会阻塞，\n而当有线程有独占锁时，其他独占和所有共享锁都会阻塞，直到独占锁解锁",[129,986,987],{"id":987},"嵌套锁",[10,989,990,991,993,994,997],{},"一个线程中",[48,992,132],{},"已经上锁后，再次上锁是错误的。而",[48,995,996],{},"std::recursive_mutex","，在同一线程可多次上锁",[10,999,1000,1001,1003,1004,1006,1007,1010,1011,1014],{},"只不过，如果调用",[48,1002,139],{},"三次，就需要",[48,1005,149],{},"三次，不过可以使用",[48,1008,1009],{},"std::lock_guard\u003Cstd::recursive_mutex>","，或者\n",[48,1012,1013],{},"std::unique_lock\u003Cstd::recursive_mutex>","来管理",[32,1016,1017],{"id":1017},"同步操作",[125,1019,1020],{"id":1020},"条件变量",[10,1022,1023,1026,1027],{},[48,1024,1025],{},"std::condition_variable","或",[48,1028,1029],{},"std::condition_variable_any",[41,1031,1033],{"className":43,"code":1032,"language":45,"meta":46,"style":46},"static std::condition_variable cond;\nstatic bool flag = false;\nstatic std::mutex m1;\n\nvoid Prepare()\n{\n  std::lock_guard\u003Cstd::mutex> lg(m1);\n  flag = true;\n  cond.notify_one();\n}\n\nvoid Process()\n{\n  std::unique_lock\u003Cstd::mutex> ul(m1);\n  cond.wait(ul, [](){return flag;});\n}\n",[48,1034,1035,1040,1045,1050,1054,1059,1063,1068,1073,1078,1082,1086,1091,1095,1100,1105],{"__ignoreMap":46},[51,1036,1037],{"class":53,"line":54},[51,1038,1039],{},"static std::condition_variable cond;\n",[51,1041,1042],{"class":53,"line":60},[51,1043,1044],{},"static bool flag = false;\n",[51,1046,1047],{"class":53,"line":66},[51,1048,1049],{},"static std::mutex m1;\n",[51,1051,1052],{"class":53,"line":72},[51,1053,169],{"emptyLinePlaceholder":168},[51,1055,1056],{"class":53,"line":78},[51,1057,1058],{},"void Prepare()\n",[51,1060,1061],{"class":53,"line":84},[51,1062,219],{},[51,1064,1065],{"class":53,"line":227},[51,1066,1067],{},"  std::lock_guard\u003Cstd::mutex> lg(m1);\n",[51,1069,1070],{"class":53,"line":233},[51,1071,1072],{},"  flag = true;\n",[51,1074,1075],{"class":53,"line":239},[51,1076,1077],{},"  cond.notify_one();\n",[51,1079,1080],{"class":53,"line":245},[51,1081,254],{},[51,1083,1084],{"class":53,"line":251},[51,1085,169],{"emptyLinePlaceholder":168},[51,1087,1088],{"class":53,"line":257},[51,1089,1090],{},"void Process()\n",[51,1092,1093],{"class":53,"line":263},[51,1094,219],{},[51,1096,1097],{"class":53,"line":268},[51,1098,1099],{},"  std::unique_lock\u003Cstd::mutex> ul(m1);\n",[51,1101,1102],{"class":53,"line":273},[51,1103,1104],{},"  cond.wait(ul, [](){return flag;});\n",[51,1106,1107],{"class":53,"line":278},[51,1108,254],{},[10,1110,1111,1114,1115,1118,1119,1121,1122,1125],{},[48,1112,1113],{},"Process()","中，如果",[48,1116,1117],{},"cond.wait()","的第二个参数为false，会解锁ul，并令线程阻塞，等待",[48,1120,1113],{},"中\n的",[48,1123,1124],{},"cond.notify_one()","唤醒，唤醒后ul上锁，重新判断第二个参数的值，如果仍为false，就继续阻塞",[41,1127,1129],{"className":43,"code":1128,"language":45,"meta":46,"style":46},"template\u003Ctypename Predicate>\nvoid minimal_wait(std::unique_lock\u003Cstd::mutex>& lk, Predicate pred)\n{\n  while(!pred())\n  {\n    lk.unlock();\n    lk.lock();\n  }\n}\n",[48,1130,1131,1136,1141,1145,1150,1154,1159,1164,1168],{"__ignoreMap":46},[51,1132,1133],{"class":53,"line":54},[51,1134,1135],{},"template\u003Ctypename Predicate>\n",[51,1137,1138],{"class":53,"line":60},[51,1139,1140],{},"void minimal_wait(std::unique_lock\u003Cstd::mutex>& lk, Predicate pred)\n",[51,1142,1143],{"class":53,"line":66},[51,1144,219],{},[51,1146,1147],{"class":53,"line":72},[51,1148,1149],{},"  while(!pred())\n",[51,1151,1152],{"class":53,"line":78},[51,1153,756],{},[51,1155,1156],{"class":53,"line":84},[51,1157,1158],{},"    lk.unlock();\n",[51,1160,1161],{"class":53,"line":227},[51,1162,1163],{},"    lk.lock();\n",[51,1165,1166],{"class":53,"line":233},[51,1167,497],{},[51,1169,1170],{"class":53,"line":239},[51,1171,254],{},[125,1173,1174],{"id":1174},"future",[10,1176,1177,1180],{},[48,1178,1179],{},"std::future\u003C>","只移动，所有权在不同实例中互相传递",[129,1182,1184],{"id":1183},"stdasync","std::async",[10,1186,1187,1188,1191,1192,1194,1195,1026,1198,1201],{},"启动一个异步任务与",[48,1189,1190],{},"std::tread","相似，返回一个",[48,1193,1179],{},"对象。当使用",[48,1196,1197],{},"get()",[48,1199,1200],{},"wait()","函数时，会阻塞线程，直到future就绪即std::async\n完成为止",[41,1203,1205],{"className":43,"code":1204,"language":45,"meta":46,"style":46},"int Foo();\nstd::future\u003Cint> result = std::async(Foo);\nstd::cout \u003C\u003C result.get() \u003C\u003C std::endl;\n",[48,1206,1207,1212,1217],{"__ignoreMap":46},[51,1208,1209],{"class":53,"line":54},[51,1210,1211],{},"int Foo();\n",[51,1213,1214],{"class":53,"line":60},[51,1215,1216],{},"std::future\u003Cint> result = std::async(Foo);\n",[51,1218,1219],{"class":53,"line":66},[51,1220,1221],{},"std::cout \u003C\u003C result.get() \u003C\u003C std::endl;\n",[10,1223,1224,1226,1227,355,1230],{},[48,1225,1184],{},"的第一个参数有",[48,1228,1229],{},"std::launch::deferred",[48,1231,1232],{},"std::launch::async",[41,1234,1236],{"className":43,"code":1235,"language":45,"meta":46,"style":46},"std::future\u003Cint> result1 = std::async(std::launch::deferred, Foo);  \u002F\u002F 在当前线程同步运行，直到get或wait时，才调用函数\nstd::future\u003Cint> result2 = std::async(std::launch::async, Foo);     \u002F\u002F 创建新线程异步运行，表示函数必须在独立线程上执行\nstd::future\u003Cint> result3 = std::async(std::launc::deferred | std::launch::async, Foo); \u002F\u002F 由系统决定\n\nresult1.wait();\nresult3.wait();\n",[48,1237,1238,1243,1248,1253,1257,1262],{"__ignoreMap":46},[51,1239,1240],{"class":53,"line":54},[51,1241,1242],{},"std::future\u003Cint> result1 = std::async(std::launch::deferred, Foo);  \u002F\u002F 在当前线程同步运行，直到get或wait时，才调用函数\n",[51,1244,1245],{"class":53,"line":60},[51,1246,1247],{},"std::future\u003Cint> result2 = std::async(std::launch::async, Foo);     \u002F\u002F 创建新线程异步运行，表示函数必须在独立线程上执行\n",[51,1249,1250],{"class":53,"line":66},[51,1251,1252],{},"std::future\u003Cint> result3 = std::async(std::launc::deferred | std::launch::async, Foo); \u002F\u002F 由系统决定\n",[51,1254,1255],{"class":53,"line":72},[51,1256,169],{"emptyLinePlaceholder":168},[51,1258,1259],{"class":53,"line":78},[51,1260,1261],{},"result1.wait();\n",[51,1263,1264],{"class":53,"line":84},[51,1265,1266],{},"result3.wait();\n",[10,1268,1269,1271],{},[48,1270,1184],{},"析构时，会阻塞线程，相当于同步执行",[41,1273,1275],{"className":43,"code":1274,"language":45,"meta":46,"style":46},"\u002F\u002F 临时变量，用完后会析构，因此do_something会等到异步任务执行完才会执行\nstd::async([]{std::cout \u003C\u003C \"hello\" \u003C\u003C std::endl;});\ndo_something();\n",[48,1276,1277,1282,1287],{"__ignoreMap":46},[51,1278,1279],{"class":53,"line":54},[51,1280,1281],{},"\u002F\u002F 临时变量，用完后会析构，因此do_something会等到异步任务执行完才会执行\n",[51,1283,1284],{"class":53,"line":60},[51,1285,1286],{},"std::async([]{std::cout \u003C\u003C \"hello\" \u003C\u003C std::endl;});\n",[51,1288,1289],{"class":53,"line":66},[51,1290,1291],{},"do_something();\n",[129,1293,1295],{"id":1294},"stdpackaged_task","std::packaged_task\u003C>",[10,1297,1298,1299,1302],{},"只是将可调用对象与future绑定，调用",[48,1300,1301],{},"std::packaged_task","对象会调用绑定的可调用对象",[41,1304,1306],{"className":43,"code":1305,"language":45,"meta":46,"style":46},"int Foo();\nstd::packaged_task\u003Cint()> task {Foo};\nstd::future\u003Cint> f = task.get_future();\ntask(); \u002F\u002F 相当于执行Foo()，运行结束后f状态为就绪，即之后f.get()或f.wait()不会阻塞\nstd::cout \u003C\u003C f.get() \u003C\u003C std::endl;\n",[48,1307,1308,1312,1317,1322,1327],{"__ignoreMap":46},[51,1309,1310],{"class":53,"line":54},[51,1311,1211],{},[51,1313,1314],{"class":53,"line":60},[51,1315,1316],{},"std::packaged_task\u003Cint()> task {Foo};\n",[51,1318,1319],{"class":53,"line":66},[51,1320,1321],{},"std::future\u003Cint> f = task.get_future();\n",[51,1323,1324],{"class":53,"line":72},[51,1325,1326],{},"task(); \u002F\u002F 相当于执行Foo()，运行结束后f状态为就绪，即之后f.get()或f.wait()不会阻塞\n",[51,1328,1329],{"class":53,"line":78},[51,1330,1331],{},"std::cout \u003C\u003C f.get() \u003C\u003C std::endl;\n",[10,1333,1334],{},"可用于线程当中",[41,1336,1338],{"className":43,"code":1337,"language":45,"meta":46,"style":46},"int Foo();\nstd::packaged_task\u003Cint()> task {Foo};\nstd::future\u003Cint> f = task.get_future();\n\nstd::thread t(task);\n...\nf.wait(); \u002F\u002F 阻塞线程，直到f就绪\n...\nt.join();\n",[48,1339,1340,1344,1348,1352,1356,1361,1365,1370,1374],{"__ignoreMap":46},[51,1341,1342],{"class":53,"line":54},[51,1343,1211],{},[51,1345,1346],{"class":53,"line":60},[51,1347,1316],{},[51,1349,1350],{"class":53,"line":66},[51,1351,1321],{},[51,1353,1354],{"class":53,"line":72},[51,1355,169],{"emptyLinePlaceholder":168},[51,1357,1358],{"class":53,"line":78},[51,1359,1360],{},"std::thread t(task);\n",[51,1362,1363],{"class":53,"line":84},[51,1364,179],{},[51,1366,1367],{"class":53,"line":227},[51,1368,1369],{},"f.wait(); \u002F\u002F 阻塞线程，直到f就绪\n",[51,1371,1372],{"class":53,"line":233},[51,1373,179],{},[51,1375,1376],{"class":53,"line":239},[51,1377,1378],{},"t.join();\n",[129,1380,1382],{"id":1381},"stdpromise","std::promise\u003C>",[10,1384,1385],{},"可以将一个值传递给一个新线程",[41,1387,1389],{"className":43,"code":1388,"language":45,"meta":46,"style":46},"auto task = [](std::future\u003Cint> f) {\n    std::cout \u003C\u003C f.get() \u003C\u003C std::flush; \u002F\u002F 阻塞，直到 p.set_value() 被调用\n};\n\nstd::promise\u003Cint> p;\nstd::thread t{ task, p.get_future() };\n\nstd::this_thread::sleep_for(std::chrono::seconds(5));\np.set_value(5);\n\nt.join();\n",[48,1390,1391,1396,1401,1405,1409,1414,1419,1423,1428,1433,1437],{"__ignoreMap":46},[51,1392,1393],{"class":53,"line":54},[51,1394,1395],{},"auto task = [](std::future\u003Cint> f) {\n",[51,1397,1398],{"class":53,"line":60},[51,1399,1400],{},"    std::cout \u003C\u003C f.get() \u003C\u003C std::flush; \u002F\u002F 阻塞，直到 p.set_value() 被调用\n",[51,1402,1403],{"class":53,"line":66},[51,1404,660],{},[51,1406,1407],{"class":53,"line":72},[51,1408,169],{"emptyLinePlaceholder":168},[51,1410,1411],{"class":53,"line":78},[51,1412,1413],{},"std::promise\u003Cint> p;\n",[51,1415,1416],{"class":53,"line":84},[51,1417,1418],{},"std::thread t{ task, p.get_future() };\n",[51,1420,1421],{"class":53,"line":227},[51,1422,169],{"emptyLinePlaceholder":168},[51,1424,1425],{"class":53,"line":233},[51,1426,1427],{},"std::this_thread::sleep_for(std::chrono::seconds(5));\n",[51,1429,1430],{"class":53,"line":239},[51,1431,1432],{},"p.set_value(5);\n",[51,1434,1435],{"class":53,"line":245},[51,1436,169],{"emptyLinePlaceholder":168},[51,1438,1439],{"class":53,"line":251},[51,1440,1378],{},[129,1442,1444],{"id":1443},"stdshared_future","std::shared_future\u003C>",[10,1446,1447,1448,1451],{},"构造",[48,1449,1450],{},"shared_future","的方法",[41,1453,1455],{"className":43,"code":1454,"language":45,"meta":46,"style":46},"std::promise\u003Cint> p;\nstd::future f(p.get_future());\nstd::shared_future\u003Cint> sf(std::move(f));\n",[48,1456,1457,1461,1466],{"__ignoreMap":46},[51,1458,1459],{"class":53,"line":54},[51,1460,1413],{},[51,1462,1463],{"class":53,"line":60},[51,1464,1465],{},"std::future f(p.get_future());\n",[51,1467,1468],{"class":53,"line":66},[51,1469,1470],{},"std::shared_future\u003Cint> sf(std::move(f));\n",[41,1472,1474],{"className":43,"code":1473,"language":45,"meta":46,"style":46},"std::promise\u003Cint> p;\nstd::shared_future\u003Cint> sf(p.get_future());\n",[48,1475,1476,1480],{"__ignoreMap":46},[51,1477,1478],{"class":53,"line":54},[51,1479,1413],{},[51,1481,1482],{"class":53,"line":60},[51,1483,1484],{},"std::shared_future\u003Cint> sf(p.get_future());\n",[41,1486,1488],{"className":43,"code":1487,"language":45,"meta":46,"style":46},"std::promise\u003Cint> p;\nauto sf = p.get_future().share();\n",[48,1489,1490,1494],{"__ignoreMap":46},[51,1491,1492],{"class":53,"line":54},[51,1493,1413],{},[51,1495,1496],{"class":53,"line":60},[51,1497,1498],{},"auto sf = p.get_future().share();\n",[125,1500,1501],{"id":1501},"锁存器和栅栏",[129,1503,1505],{"id":1504},"stdlatch","std::latch",[14,1507,1508,1514,1523],{},[17,1509,1510,1511],{},"计数器作为构造函数的唯一参数",[48,1512,1513],{},"std::latch la(3)",[17,1515,1516,355,1519,1522],{},[48,1517,1518],{},"count_down()",[48,1520,1521],{},"arrive_and_wait()"," 令计数器减一，而后者会阻塞线程直到计数器为0",[17,1524,1525,1527],{},[48,1526,1200],{},"阻塞线程，直到计数器为0",[129,1529,1531],{"id":1530},"stdbarrier","std::barrier",[14,1533,1534,1567,1572,1587],{},[17,1535,1536,1537],{},"计数器作为第一个参数，可调用对象(必须是noexcept)作为第二个参数(可选)，在barrier就绪(计数器为0)时，\n其中一个线程调用。同时，返回值指定下一次的计数",[41,1538,1540],{"className":43,"code":1539,"language":45,"meta":46,"style":46},"std::barrier b1(3);\nstd::barrier b2(3, []() noexcept {\n  std::cout \u003C\u003C std::this_thread::get_id() \u003C\u003C std::endl;\n  return -1; \u002F\u002F -1表示下一次计数不变\n});\n",[48,1541,1542,1547,1552,1557,1562],{"__ignoreMap":46},[51,1543,1544],{"class":53,"line":54},[51,1545,1546],{},"std::barrier b1(3);\n",[51,1548,1549],{"class":53,"line":60},[51,1550,1551],{},"std::barrier b2(3, []() noexcept {\n",[51,1553,1554],{"class":53,"line":66},[51,1555,1556],{},"  std::cout \u003C\u003C std::this_thread::get_id() \u003C\u003C std::endl;\n",[51,1558,1559],{"class":53,"line":72},[51,1560,1561],{},"  return -1; \u002F\u002F -1表示下一次计数不变\n",[51,1563,1564],{"class":53,"line":78},[51,1565,1566],{},"});\n",[17,1568,1569,1571],{},[48,1570,1521],{},"令计数器减一，并且阻塞线程",[17,1573,1574,355,1577,1579,1580,355,1583,1586],{},[48,1575,1576],{},"arrive()",[48,1578,1200],{},"，",[48,1581,1582],{},"b.arrive(b.wait())",[48,1584,1585],{},"b.arrive_and_wait()","等价",[17,1588,1589,1592,1593],{},[48,1590,1591],{},"arrive_and_drop()","，当前计数与下次barrier计数减一",[1594,1595,1596],"blockquote",{},[10,1597,1598],{},"std::barrier可多次使用",[32,1600,1601],{"id":1601},"内存模型和原子操作",[125,1603,1604],{"id":1604},"atomic",[10,1606,1607,1608,1611,1612,1615,1616,1618],{},"atomic的操作都是原子的，有的是使用原子指令，有的使用互斥锁模拟原子操作，使用",[48,1609,1610],{},"x.is_lock_free()","\n函数查询原子指令(",[48,1613,1614],{},"is_lock_free()","返回true)还是使用锁(",[48,1617,1614],{},"返回false)",[10,1620,1621,1622,1625],{},"同时C++17中，所有原子类型有一个static constexpr成员变量",[48,1623,1624],{},"X::is_always_lock_free","，值为true\n表示无锁，false表示有锁",[129,1627,1629],{"id":1628},"stdatomic_flag","std::atomic_flag",[1594,1631,1632],{},[10,1633,1634],{},"唯一确保为无锁的类型",[10,1636,1637,1639,1640,1643],{},[48,1638,1629],{},"对象必须被",[48,1641,1642],{},"ATOMIC_FLAG_INIT","初始化。初始化标志位为清除状态即false",[41,1645,1647],{"className":43,"code":1646,"language":45,"meta":46,"style":46},"class spinlock_mutex\n{\nprivate:\n  std::atomic_flag flag;\npublic:\n  spinlock_mutex() : flag(ATOMIC_FLAG_INIT) {}\n  lock()\n  {\n    \u002F\u002F test_and_set()设置标志位为true，并返回旧的标志位\n    \u002F\u002F 第一次调用或着clear()后，才会返回false，从而调出循环\n    while(flag.test_and_set(std::memory_order_acquire));\n  }\n  unlock()\n  {\n    \u002F\u002F 设置标志位为false\n    flag.clear(std::memory_order_release);\n  }\n};\n",[48,1648,1649,1654,1658,1662,1667,1671,1676,1681,1685,1690,1695,1700,1704,1709,1713,1718,1723,1727],{"__ignoreMap":46},[51,1650,1651],{"class":53,"line":54},[51,1652,1653],{},"class spinlock_mutex\n",[51,1655,1656],{"class":53,"line":60},[51,1657,219],{},[51,1659,1660],{"class":53,"line":66},[51,1661,575],{},[51,1663,1664],{"class":53,"line":72},[51,1665,1666],{},"  std::atomic_flag flag;\n",[51,1668,1669],{"class":53,"line":78},[51,1670,462],{},[51,1672,1673],{"class":53,"line":84},[51,1674,1675],{},"  spinlock_mutex() : flag(ATOMIC_FLAG_INIT) {}\n",[51,1677,1678],{"class":53,"line":227},[51,1679,1680],{},"  lock()\n",[51,1682,1683],{"class":53,"line":233},[51,1684,756],{},[51,1686,1687],{"class":53,"line":239},[51,1688,1689],{},"    \u002F\u002F test_and_set()设置标志位为true，并返回旧的标志位\n",[51,1691,1692],{"class":53,"line":245},[51,1693,1694],{},"    \u002F\u002F 第一次调用或着clear()后，才会返回false，从而调出循环\n",[51,1696,1697],{"class":53,"line":251},[51,1698,1699],{},"    while(flag.test_and_set(std::memory_order_acquire));\n",[51,1701,1702],{"class":53,"line":257},[51,1703,497],{},[51,1705,1706],{"class":53,"line":263},[51,1707,1708],{},"  unlock()\n",[51,1710,1711],{"class":53,"line":268},[51,1712,756],{},[51,1714,1715],{"class":53,"line":273},[51,1716,1717],{},"    \u002F\u002F 设置标志位为false\n",[51,1719,1720],{"class":53,"line":278},[51,1721,1722],{},"    flag.clear(std::memory_order_release);\n",[51,1724,1725],{"class":53,"line":284},[51,1726,497],{},[51,1728,1729],{"class":53,"line":290},[51,1730,660],{},[129,1732,1734],{"id":1733},"stdatomicbool","std::atomic\u003Cbool>",[10,1736,1737,1740,1741,355,1744],{},[48,1738,1739],{},"load()",", ",[48,1742,1743],{},"store()",[48,1745,1746],{},"exchange()",[41,1748,1750],{"className":43,"code":1749,"language":45,"meta":46,"style":46},"atd::atomic\u003Cbool> b;\nbool x = b.load(std::memory_order_acquire);\nb.store(true);\n\u002F\u002F exchange()会返回旧值\nx = b.exchange(true, std::memory_order_acq_rel);\n",[48,1751,1752,1757,1762,1767,1772],{"__ignoreMap":46},[51,1753,1754],{"class":53,"line":54},[51,1755,1756],{},"atd::atomic\u003Cbool> b;\n",[51,1758,1759],{"class":53,"line":60},[51,1760,1761],{},"bool x = b.load(std::memory_order_acquire);\n",[51,1763,1764],{"class":53,"line":66},[51,1765,1766],{},"b.store(true);\n",[51,1768,1769],{"class":53,"line":72},[51,1770,1771],{},"\u002F\u002F exchange()会返回旧值\n",[51,1773,1774],{"class":53,"line":78},[51,1775,1776],{},"x = b.exchange(true, std::memory_order_acq_rel);\n",[10,1778,1779,787,1782],{},[48,1780,1781],{},"compare_exchange_weak()",[48,1783,1784],{},"compare_exchange_strong()",[1594,1786,1787],{},[10,1788,1789,1790,355,1792,1794],{},"CAS即Compare And Swap，",[48,1791,1781],{},[48,1793,1784],{},"是C++对CAS的实现",[10,1796,1797,1800,1801,1804],{},[48,1798,1799],{},"x.compare_exchange_strong(expected, desired)","，如果x的原始值(",[48,1802,1803],{},"*this",")与期望值(expected)相同，\n则令x的值为desired，并返回ture，如果不同，则x的值不变，并将值赋给expected，返回false",[1594,1806,1807],{},[10,1808,1809],{},"返回值true或false表示x的值是否变化，与期望值相同则改变，不同则没变",[41,1811,1813],{"className":43,"code":1812,"language":45,"meta":46,"style":46},"bool expected = false;\nextern std::atomic\u003Cbool> b;\nif(b.compare_exchange_strong(expected, true))\n{\n  ...\n}\n",[48,1814,1815,1820,1825,1830,1834,1838],{"__ignoreMap":46},[51,1816,1817],{"class":53,"line":54},[51,1818,1819],{},"bool expected = false;\n",[51,1821,1822],{"class":53,"line":60},[51,1823,1824],{},"extern std::atomic\u003Cbool> b;\n",[51,1826,1827],{"class":53,"line":66},[51,1828,1829],{},"if(b.compare_exchange_strong(expected, true))\n",[51,1831,1832],{"class":53,"line":72},[51,1833,219],{},[51,1835,1836],{"class":53,"line":78},[51,1837,236],{},[51,1839,1840],{"class":53,"line":84},[51,1841,254],{},[10,1843,1844,1845,1847,1848,1851,1852,1854],{},"对于",[48,1846,1781],{},"来说，可能会出现\"伪失败\"，即",[48,1849,1850],{},"x.compare_exchange_weak(y, z)","，在\nx与y相等时，仍然返回false，且将x的值赋给y。所以通常在使用",[48,1853,1781],{},"时，都需要一个\n循环",[41,1856,1858],{"className":43,"code":1857,"language":45,"meta":46,"style":46},"\u002F\u002F x与expected相等时，如果伪失败，将x的值赋给expected后，再进行一次CAS\nwhile(!x.compare_exchange_weak(expected, desired));\n",[48,1859,1860,1865],{"__ignoreMap":46},[51,1861,1862],{"class":53,"line":54},[51,1863,1864],{},"\u002F\u002F x与expected相等时，如果伪失败，将x的值赋给expected后，再进行一次CAS\n",[51,1866,1867],{"class":53,"line":60},[51,1868,1869],{},"while(!x.compare_exchange_weak(expected, desired));\n",[129,1871,1873],{"id":1872},"stdatomict","std::atomic\u003CT*>",[10,1875,1876,1877,355,1880,1883],{},"提供+=、-=、++、--操作，同时",[48,1878,1879],{},"fetch_add()",[48,1881,1882],{},"fetch_sub()","在加、减的基础上返回原来的值，称为\n\"交换-相加\"",[41,1885,1887],{"className":43,"code":1886,"language":45,"meta":46,"style":46},"class Widget {};\nWidget a[3];\nstd::atmoic\u003CWidget*> p {a};\n\nWidget* w1 = p.fetch_add(1); \u002F\u002F p加1，而w1是p的原始值\n",[48,1888,1889,1894,1899,1904,1908],{"__ignoreMap":46},[51,1890,1891],{"class":53,"line":54},[51,1892,1893],{},"class Widget {};\n",[51,1895,1896],{"class":53,"line":60},[51,1897,1898],{},"Widget a[3];\n",[51,1900,1901],{"class":53,"line":66},[51,1902,1903],{},"std::atmoic\u003CWidget*> p {a};\n",[51,1905,1906],{"class":53,"line":72},[51,1907,169],{"emptyLinePlaceholder":168},[51,1909,1910],{"class":53,"line":78},[51,1911,1912],{},"Widget* w1 = p.fetch_add(1); \u002F\u002F p加1，而w1是p的原始值\n",[129,1914,1916],{"id":1915},"stdatomic","std::atomic\u003C>",[125,1918,1919],{"id":1919},"原子操作的内存序",[1921,1922,1923,1928,1933,1938,1943,1948],"ol",{},[17,1924,1925],{},[48,1926,1927],{},"memory_order_relaxed",[17,1929,1930],{},[48,1931,1932],{},"memory_order_consume",[17,1934,1935],{},[48,1936,1937],{},"memory_order_acquire",[17,1939,1940],{},[48,1941,1942],{},"memory_order_release",[17,1944,1945],{},[48,1946,1947],{},"memory_order_acq_rel",[17,1949,1950],{},[48,1951,1952],{},"memory_order_seq_cst",[10,1954,1955,1956],{},"除非指定一个选项，不然默认都是",[48,1957,1952],{},[10,1959,1960,1961,1740,1963,1965,1966,787,1968,1970,1971,1973],{},"6种选项代表三种内存模型：顺序一致性，获取-释放序(",[48,1962,1932],{},[48,1964,1937],{},",\n",[48,1967,1942],{},[48,1969,1947],{},")和自由序(",[48,1972,1927],{},")",[10,1975,1976],{},"memory order针对的是共享变量，可以是atomic也可以是non-atomic的，但一定是共享的，通过\nmemory order约定CPU操作变量的顺序",[129,1978,1979],{"id":1979},"顺序一致性",[1921,1981,1982,1985],{},[17,1983,1984],{},"操作不重排，以源码的顺序执行",[17,1986,1987],{},"当前线程的操作顺序，对于其他线程可见",[10,1989,1990],{},"producer的线程中的代码顺序不会改变，即3先行于4，该顺序对consumer可见。因此在运行1\n时，知道先运行3再运行4",[41,1992,1994],{"className":43,"code":1993,"language":45,"meta":46,"style":46},"std::atomic\u003Cbool> ready { false };\nstd::string work = \" \";\n\nvoid consumer()\n{\n  while(!ready.load());           \u002F\u002F 1\n  std::cout \u003C\u003C work \u003C\u003C std::endl; \u002F\u002F 2\n}\n\nvoid producer()\n{\n  work = \"done\";     \u002F\u002F 3\n  ready.store(true); \u002F\u002F 4\n}\n\nint main()\n{\n  std::thread t1(producer);\n  std::thread t2(consumer);\n  t1.join();\n  t2.join();\n}\n",[48,1995,1996,2001,2006,2010,2015,2019,2024,2029,2033,2037,2042,2046,2051,2056,2060,2064,2069,2073,2078,2083,2088,2093],{"__ignoreMap":46},[51,1997,1998],{"class":53,"line":54},[51,1999,2000],{},"std::atomic\u003Cbool> ready { false };\n",[51,2002,2003],{"class":53,"line":60},[51,2004,2005],{},"std::string work = \" \";\n",[51,2007,2008],{"class":53,"line":66},[51,2009,169],{"emptyLinePlaceholder":168},[51,2011,2012],{"class":53,"line":72},[51,2013,2014],{},"void consumer()\n",[51,2016,2017],{"class":53,"line":78},[51,2018,219],{},[51,2020,2021],{"class":53,"line":84},[51,2022,2023],{},"  while(!ready.load());           \u002F\u002F 1\n",[51,2025,2026],{"class":53,"line":227},[51,2027,2028],{},"  std::cout \u003C\u003C work \u003C\u003C std::endl; \u002F\u002F 2\n",[51,2030,2031],{"class":53,"line":233},[51,2032,254],{},[51,2034,2035],{"class":53,"line":239},[51,2036,169],{"emptyLinePlaceholder":168},[51,2038,2039],{"class":53,"line":245},[51,2040,2041],{},"void producer()\n",[51,2043,2044],{"class":53,"line":251},[51,2045,219],{},[51,2047,2048],{"class":53,"line":257},[51,2049,2050],{},"  work = \"done\";     \u002F\u002F 3\n",[51,2052,2053],{"class":53,"line":263},[51,2054,2055],{},"  ready.store(true); \u002F\u002F 4\n",[51,2057,2058],{"class":53,"line":268},[51,2059,254],{},[51,2061,2062],{"class":53,"line":273},[51,2063,169],{"emptyLinePlaceholder":168},[51,2065,2066],{"class":53,"line":278},[51,2067,2068],{},"int main()\n",[51,2070,2071],{"class":53,"line":284},[51,2072,219],{},[51,2074,2075],{"class":53,"line":290},[51,2076,2077],{},"  std::thread t1(producer);\n",[51,2079,2080],{"class":53,"line":296},[51,2081,2082],{},"  std::thread t2(consumer);\n",[51,2084,2085],{"class":53,"line":301},[51,2086,2087],{},"  t1.join();\n",[51,2089,2090],{"class":53,"line":306},[51,2091,2092],{},"  t2.join();\n",[51,2094,2095],{"class":53,"line":311},[51,2096,254],{},[129,2098,2099],{"id":2099},"获取-释放序",[1594,2101,2102],{},[10,2103,2104],{},"在线程A上一个原子存储是释放操作，在线程B上对相同变量的原子加载时获得操作，且\n线程B上的加载读取由线程A上的存储写入的值，则线程A上的存储Synchronizes-with(同步发生)线程B上的加载",[14,2106,2107,2110],{},[17,2108,2109],{},"不许acquire之后的操作重排到acquire之前，其他release同一原子变量的线程的所有\n写入对当前线程可见",[17,2111,2112],{},"不许release之前的操作重排到release之后，当前线程的所有写入，可见于获得该同一\n原子变量的其他线程",[10,2114,2115,2116,2118,2119,2121,2122,2124,2125],{},"关于",[48,2117,1932],{},"，与",[48,2120,1937],{},"一样，必须与",[48,2123,1942],{},"一起使用，\n",[2126,2127,2128],"del",{},"然后就看不懂了，后续再补充",[129,2130,2131],{"id":2131},"自由序",[10,2133,2134],{},"没有任何同步和重排限制",[125,2136,2137],{"id":2137},"栅栏",[10,2139,1844,2140,355,2142,2144,2145,2147,2148,2150],{},[48,2141,139],{},[48,2143,149],{},"，可以看作两个单方向的屏障，",[48,2146,139],{},"只允许向下方移动，\n",[48,2149,149],{},"只允许向上方移动",[10,2152,2153],{},[2154,2155],"img",{"alt":2156,"src":2157},"move-out","https:\u002F\u002Fstarrobe-blog.oss-cn-beijing.aliyuncs.com\u002Fimages\u002Fmove_out.png",[10,2159,2160],{},[2154,2161],{"alt":2162,"src":2163},"move-in","https:\u002F\u002Fstarrobe-blog.oss-cn-beijing.aliyuncs.com\u002Fimages\u002Fmove_in.png",[2165,2166,2167,2184],"table",{},[2168,2169,2170],"thead",{},[2171,2172,2173,2178,2181],"tr",{},[2174,2175,2177],"th",{"align":2176},"left","full fence",[2174,2179,2180],{"align":2176},"acquire fence",[2174,2182,2183],{"align":2176},"release fence",[2185,2186,2187,2205],"tbody",{},[2171,2188,2189,2195,2200],{},[2190,2191,2192],"td",{"align":2176},[48,2193,2194],{},"std::atomic_thread_fence()",[2190,2196,2197],{"align":2176},[48,2198,2199],{},"std::atomic_thread_fence(std::memory_order_acquire)",[2190,2201,2202],{"align":2176},[48,2203,2204],{},"std::atomic_thread_fence(std::memory_order_release)",[2171,2206,2207,2210,2213],{},[2190,2208,2209],{"align":2176},"避免重排(Store-Load除外)",[2190,2211,2212],{"align":2176},"避免栅栏前的读操作，被栅栏后的操作重排",[2190,2214,2215],{"align":2176},"避免栅栏前的写擦欧总，被栅栏前的操作重排",[10,2217,2218],{},[2154,2219],{"alt":2220,"src":2221},"fences","https:\u002F\u002Fstarrobe-blog.oss-cn-beijing.aliyuncs.com\u002Fimages\u002Ffences.png",[129,2223,2177],{"id":2224},"full-fence",[10,2226,2227],{},[2154,2228],{"alt":2224,"src":2229},"https:\u002F\u002Fstarrobe-blog.oss-cn-beijing.aliyuncs.com\u002Fimages\u002Ffull_fence.png",[129,2231,2180],{"id":2232},"acquire-fence",[10,2234,2235],{},[2154,2236],{"alt":2232,"src":2237},"https:\u002F\u002Fstarrobe-blog.oss-cn-beijing.aliyuncs.com\u002Fimages\u002Facquire_fence.png",[129,2239,2183],{"id":2240},"release-fence",[10,2242,2243],{},[2154,2244],{"alt":2240,"src":2245},"https:\u002F\u002Fstarrobe-blog.oss-cn-beijing.aliyuncs.com\u002Fimages\u002Frelease_fence.png",[2247,2248],"hr",{},[10,2250,2251,2252],{},"待续。。。",[2126,2253,2254],{},"有时间再看后面的",[2256,2257,2258],"style",{},"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);}",{"title":46,"searchDepth":60,"depth":60,"links":2260},[2261,2262,2266,2271],{"id":34,"depth":60,"text":34},{"id":123,"depth":60,"text":123,"children":2263},[2264,2265],{"id":127,"depth":66,"text":127},{"id":710,"depth":66,"text":710},{"id":1017,"depth":60,"text":1017,"children":2267},[2268,2269,2270],{"id":1020,"depth":66,"text":1020},{"id":1174,"depth":66,"text":1174},{"id":1501,"depth":66,"text":1501},{"id":1601,"depth":60,"text":1601,"children":2272},[2273,2274,2275],{"id":1604,"depth":66,"text":1604},{"id":1919,"depth":66,"text":1919},{"id":2137,"depth":66,"text":2137},"2023-07-24","笔记","md",{},"\u002Fblog\u002Fcplusplus-concurrency",{"title":5,"description":2277},"blog\u002Fcplusplus-concurrency",[2284,2285],"C++","并发编程","JAvcJa3vDr3fIa9rUig4beZFZOMpUW2pmGaKHQpjw-o",{"id":2288,"title":2289,"avatar":2290,"body":2291,"description":2295,"extension":2278,"meta":2296,"name":2298,"navigation":168,"path":2299,"seo":2300,"social":2301,"stem":2307,"__hash__":2308},"home\u002Fhome.md","Home","https:\u002F\u002Fstarrobe-blog.oss-cn-beijing.aliyuncs.com\u002Favatar\u002Fjashinchan.jpg",{"type":7,"value":2292,"toc":2293},[],{"title":46,"searchDepth":60,"depth":60,"links":2294},[],"Programming enthusiast, maybe.",{"layout":2297},"page","阿东","\u002Fhome",{"title":2289,"description":2295},{"github":2302,"email":2303,"bilibili":2304,"qq":2305,"rss":2306},"https:\u002F\u002Fgithub.com\u002Fstarrobe","mailto:starrobe@163.com","https:\u002F\u002Fspace.bilibili.com\u002F382631863","tencent:\u002F\u002Fmessage\u002F?uin=2604335528","\u002Ffeed.xml","home","XHOrpn2fXb8x87SMsqZTGaANCESyH9qV8TDm8rnQewI",1777128585725]