在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ C/ A.5 Lambda函數(shù)
3.4 本章總結(jié)
6.3 基于鎖設(shè)計(jì)更加復(fù)雜的數(shù)據(jù)結(jié)構(gòu)
6.1 為并發(fā)設(shè)計(jì)的意義何在?
5.2 <code>C++</code>中的原子操作和原子類型
A.7 自動(dòng)推導(dǎo)變量類型
2.1 線程管理的基礎(chǔ)
8.5 在實(shí)踐中設(shè)計(jì)并發(fā)代碼
2.4 運(yùn)行時(shí)決定線程數(shù)量
2.2 向線程函數(shù)傳遞參數(shù)
第4章 同步并發(fā)操作
2.3 轉(zhuǎn)移線程所有權(quán)
8.3 為多線程性能設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)
6.4 本章總結(jié)
7.3 對(duì)于設(shè)計(jì)無(wú)鎖數(shù)據(jù)結(jié)構(gòu)的指導(dǎo)建議
關(guān)于這本書
A.1 右值引用
2.6 本章總結(jié)
D.2 &lt;condition_variable&gt;頭文件
A.6 變參模板
6.2 基于鎖的并發(fā)數(shù)據(jù)結(jié)構(gòu)
4.5 本章總結(jié)
A.9 本章總結(jié)
前言
第10章 多線程程序的測(cè)試和調(diào)試
5.4 本章總結(jié)
第9章 高級(jí)線程管理
5.1 內(nèi)存模型基礎(chǔ)
2.5 識(shí)別線程
第1章 你好,C++的并發(fā)世界!
1.2 為什么使用并發(fā)?
A.5 Lambda函數(shù)
第2章 線程管理
4.3 限定等待時(shí)間
D.3 &lt;atomic&gt;頭文件
10.2 定位并發(fā)錯(cuò)誤的技術(shù)
附錄B 并發(fā)庫(kù)的簡(jiǎn)單比較
5.3 同步操作和強(qiáng)制排序
A.8 線程本地變量
第8章 并發(fā)代碼設(shè)計(jì)
3.3 保護(hù)共享數(shù)據(jù)的替代設(shè)施
附錄D C++線程庫(kù)參考
第7章 無(wú)鎖并發(fā)數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)
D.7 &lt;thread&gt;頭文件
D.1 &lt;chrono&gt;頭文件
4.1 等待一個(gè)事件或其他條件
A.3 默認(rèn)函數(shù)
附錄A 對(duì)<code>C++</code>11語(yǔ)言特性的簡(jiǎn)要介紹
第6章 基于鎖的并發(fā)數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)
封面圖片介紹
7.2 無(wú)鎖數(shù)據(jù)結(jié)構(gòu)的例子
8.6 本章總結(jié)
8.1 線程間劃分工作的技術(shù)
4.2 使用期望等待一次性事件
8.4 設(shè)計(jì)并發(fā)代碼的注意事項(xiàng)
D.5 &lt;mutex&gt;頭文件
3.1 共享數(shù)據(jù)帶來的問題
資源
9.3 本章總結(jié)
10.3 本章總結(jié)
10.1 與并發(fā)相關(guān)的錯(cuò)誤類型
D.4 &lt;future&gt;頭文件
3.2 使用互斥量保護(hù)共享數(shù)據(jù)
9.1 線程池
1.1 何謂并發(fā)
9.2 中斷線程
4.4 使用同步操作簡(jiǎn)化代碼
A.2 刪除函數(shù)
1.3 C++中的并發(fā)和多線程
1.4 開始入門
第5章 C++內(nèi)存模型和原子類型操作
消息傳遞框架與完整的ATM示例
8.2 影響并發(fā)代碼性能的因素
7.1 定義和意義
D.6 &lt;ratio&gt;頭文件
A.4 常量表達(dá)式函數(shù)
7.4 本章總結(jié)
1.5 本章總結(jié)
第3章 線程間共享數(shù)據(jù)

A.5 Lambda函數(shù)

lambda函數(shù)在C++11中的加入很是令人興奮,因?yàn)閘ambda函數(shù)能夠大大簡(jiǎn)化代碼復(fù)雜度(語(yǔ)法糖:利于理解具體的功能),避免實(shí)現(xiàn)調(diào)用對(duì)象。C++11的lambda函數(shù)語(yǔ)法允許在需要使用的時(shí)候進(jìn)行定義。能為等待函數(shù),例如std::condition_variable(如同4.1.1節(jié)中的例子)提供很好謂詞函數(shù),其語(yǔ)義可以用來快速的表示可訪問的變量,而非使用類中函數(shù)來對(duì)成員變量進(jìn)行捕獲。

最簡(jiǎn)單的情況下,lambda表達(dá)式就一個(gè)自給自足的函數(shù),不需要傳入函數(shù)僅依賴管局變量和函數(shù),甚至都可以不用返回一個(gè)值。這樣的lambda表達(dá)式的一系列語(yǔ)義都需要封閉在括號(hào)中,還要以方括號(hào)作為前綴:

[]{  // lambda表達(dá)式以[]開始
  do_stuff();
  do_more_stuff();
}();  // 表達(dá)式結(jié)束,可以直接調(diào)用

例子中,lambda表達(dá)式通過后面的括號(hào)調(diào)用,不過這種方式不常用。一方面,如果想要直接調(diào)用,可以在寫完對(duì)應(yīng)的語(yǔ)句后,就對(duì)函數(shù)進(jìn)行調(diào)用。對(duì)于函數(shù)模板,傳遞一個(gè)參數(shù)進(jìn)去時(shí)很常見的事情,甚至可以將可調(diào)用對(duì)象作為其參數(shù)傳入;可調(diào)用對(duì)象通常也需要一些參數(shù),或返回一個(gè)值,亦或兩者都有。如果想給lambda函數(shù)傳遞參數(shù),可以參考下面的lambda函數(shù),其使用起來就像是一個(gè)普通函數(shù)。例如,下面代碼是將vector中的元素使用std::cout進(jìn)行打?。?/p>

std::vector<int> data=make_data();
std::for_each(data.begin(),data.end(),[](int i){std::cout<<i<<"\n";});

返回值也是很簡(jiǎn)單的,當(dāng)lambda函數(shù)體包括一個(gè)return語(yǔ)句,返回值的類型就作為lambda表達(dá)式的返回類型。例如,使用一個(gè)簡(jiǎn)單的lambda函數(shù)來等待std::condition_variable(見4.1.1節(jié))中的標(biāo)志被設(shè)置。

清單A.4 lambda函數(shù)推導(dǎo)返回類型

std::condition_variable cond;
bool data_ready;
std::mutex m;
void wait_for_data()
{
  std::unique_lock<std::mutex> lk(m);
  cond.wait(lk,[]{return data_ready;});  // 1
}

lambda的返回值傳遞給cond.wait()①,函數(shù)就能推斷出data_ready的類型是bool。當(dāng)條件變量從等待中蘇醒后,上鎖階段會(huì)調(diào)用lambda函數(shù),并且當(dāng)data_ready為true時(shí),僅返回到wait()中。

當(dāng)lambda函數(shù)體中有多個(gè)return語(yǔ)句,就需要顯式的指定返回類型。只有一個(gè)返回語(yǔ)句的時(shí)候,也可以這樣做,不過這樣可能會(huì)讓你的lambda函數(shù)體看起來更復(fù)雜。返回類型可以使用跟在參數(shù)列表后面的箭頭(->)進(jìn)行設(shè)置。如果lambda函數(shù)沒有任何參數(shù),還需要包含(空)的參數(shù)列表,這樣做是為了能顯式的對(duì)返回類型進(jìn)行指定。對(duì)條件變量的預(yù)測(cè)可以寫成下面這種方式:

cond.wait(lk,[]()->bool{return data_ready;});

還可以對(duì)lambda函數(shù)進(jìn)行擴(kuò)展,比如:加上log信息的打印,或做更加復(fù)雜的操作:

cond.wait(lk,[]()->bool{
  if(data_ready)
  {
    std::cout<<”Data ready”<<std::endl;
    return true;
  }
  else
  {
    std::cout<<”Data not ready, resuming wait”<<std::endl;
    return false;
  }
});

雖然簡(jiǎn)單的lambda函數(shù)很強(qiáng)大,能簡(jiǎn)化代碼,不過其真正的強(qiáng)大的地方在于對(duì)本地變量的捕獲。

A.5.1 引用本地變量的Lambda函數(shù)

lambda函數(shù)使用空的[](lambda introducer)就不能引用當(dāng)前范圍內(nèi)的本地變量;其只能使用全局變量,或?qū)⑵渌狄詤?shù)的形式進(jìn)行傳遞。當(dāng)想要訪問一個(gè)本地變量,需要對(duì)其進(jìn)行捕獲。最簡(jiǎn)單的方式就是將范圍內(nèi)的所有本地變量都進(jìn)行捕獲,使用[=]就可以完成這樣的功能。函數(shù)被創(chuàng)建的時(shí)候,就能對(duì)本地變量的副本進(jìn)行訪問了。

實(shí)踐一下,看一下下面的例子:

std::function<int(int)> make_offseter(int offset)
{
  return [=](int j){return offset+j;};
}

當(dāng)調(diào)用make_offseter時(shí),就會(huì)通過std::function<>函數(shù)包裝返回一個(gè)新的lambda函數(shù)體。

這個(gè)帶有返回的函數(shù)添加了對(duì)參數(shù)的偏移功能。例如:

int main()
{
  std::function<int(int)> offset_42=make_offseter(42);
  std::function<int(int)> offset_123=make_offseter(123);
  std::cout<<offset_42(12)<<”,“<<offset_123(12)<<std::endl;
  std::cout<<offset_42(12)<<”,“<<offset_123(12)<<std::endl;
}

屏幕上將打印出54,135兩次,因?yàn)榈谝淮螐膍ake_offseter中返回,都是對(duì)參數(shù)加42的;第二次調(diào)用后,make_offseter會(huì)對(duì)參數(shù)加上123。所以,會(huì)打印兩次相同的值。

這種本地變量捕獲的方式相當(dāng)安全,所有的東西都進(jìn)行了拷貝,所以可以通過lambda函數(shù)對(duì)表達(dá)式的值進(jìn)行返回,并且可在原始函數(shù)之外的地方對(duì)其進(jìn)行調(diào)用。這也不是唯一的選擇,也可以通過選擇通過引用的方式捕獲本地變量。在本地變量被銷毀的時(shí)候,lambda函數(shù)會(huì)出現(xiàn)未定義的行為。

下面的例子,就介紹一下怎么使用[&]對(duì)所有本地變量進(jìn)行引用:

int main()
{
  int offset=42;  // 1
  std::function<int(int)> offset_a=[&](int j){return offset+j;};  // 2
  offset=123;  // 3
  std::function<int(int)> offset_b=[&](int j){return offset+j;};  // 4
  std::cout<<offset_a(12)<<”,”<<offset_b(12)<<std::endl;  // 5
  offset=99;  // 6
  std::cout<<offset_a(12)<<”,”<<offset_b(12)<<std::endl;  // 7
}

之前的例子中,使用[=]來對(duì)要偏移的變量進(jìn)行拷貝,offset_a函數(shù)就是個(gè)使用[&]捕獲offset的引用的例子②。所以,offset初始化成42也沒什么關(guān)系①;offset_a(12)的例子通常會(huì)依賴與當(dāng)前offset的值。在③上,offset的值會(huì)變?yōu)?23,offset_b④函數(shù)將會(huì)使用到這個(gè)值,同樣第二個(gè)函數(shù)也是使用引用的方式。

現(xiàn)在,第一行打印信息⑤,offset為123,所以輸出為135,135。不過,第二行打印信息⑦就有所不同,offset變成99⑥,所以輸出為111,111。offset_a和offset_b都對(duì)當(dāng)前值進(jìn)行了加12的操作。

塵歸塵,土歸土,C++還是C++;這些選項(xiàng)不會(huì)讓你感覺到特別困惑,你可以選擇以引用或拷貝的方式對(duì)變量進(jìn)行捕獲,并且你還可以通過調(diào)整中括號(hào)中的表達(dá)式,來對(duì)特定的變量進(jìn)行顯式捕獲。如果想要拷貝所有變量,而非一兩個(gè),可以使用[=],通過參考中括號(hào)中的符號(hào),對(duì)變量進(jìn)行捕獲。下面的例子將會(huì)打印出1239,因?yàn)閕是拷貝進(jìn)lambda函數(shù)中的,而j和k是通過引用的方式進(jìn)行捕獲的:

int main()
{
  int i=1234,j=5678,k=9;
  std::function<int()> f=[=,&j,&k]{return i+j+k;};
  i=1;
  j=2;
  k=3;
  std::cout<<f()<<std::endl;
}

或者,也可以通過默認(rèn)引用方式對(duì)一些變量做引用,而對(duì)一些特別的變量進(jìn)行拷貝。這種情況下,就要使用[&]與拷貝符號(hào)相結(jié)合的方式對(duì)列表中的變量進(jìn)行拷貝捕獲。下面的例子將打印出5688,因?yàn)閕通過引用捕獲,但j和k 通過拷貝捕獲:

int main()
{
  int i=1234,j=5678,k=9;
  std::function<int()> f=[&,j,k]{return i+j+k;};
  i=1;
  j=2;
  k=3;
  std::cout<<f()<<std::endl;
}

如果你只想捕獲某些變量,那么你可以忽略=或&,僅使用變量名進(jìn)行捕獲就行;加上&前綴,是將對(duì)應(yīng)變量以引用的方式進(jìn)行捕獲,而非拷貝的方式。下面的例子將打印出5682,因?yàn)閕和k是通過引用的范式獲取的,而j是通過拷貝的方式:

int main()
{
  int i=1234,j=5678,k=9;
  std::function<int()> f=[&i,j,&k]{return i+j+k;};
  i=1;
  j=2;
  k=3;
  std::cout<<f()<<std::endl;
}

最后一種方式,是為了確保預(yù)期的變量能被捕獲,在捕獲列表中引用任何不存在的變量都會(huì)引起編譯錯(cuò)誤。當(dāng)選擇這種方式,就要小心類成員的訪問方式,確定類中是否包含一個(gè)lambda函數(shù)的成員變量。類成員變量不能直接捕獲,如果想通過lambda方式訪問類中的成員,需要在捕獲列表中添加this指針,以便捕獲。下面的例子中,lambda捕獲this后,就能訪問到some_data類中的成員:

struct X
{
  int some_data;
  void foo(std::vector<int>& vec)
  {
    std::for_each(vec.begin(),vec.end(),
         [this](int& i){i+=some_data;});
  }
};

并發(fā)的上下文中,lambda是很有用的,其可以作為謂詞放在std::condition_variable::wait()(見4.1.1節(jié))和std::packaged_task<>(見4.2.1節(jié))中;或是用在線程池中,對(duì)小任務(wù)進(jìn)行打包。也可以線程函數(shù)的方式std::thread的構(gòu)造函數(shù)(見2.1.1),以及作為一個(gè)并行算法實(shí)現(xiàn),在parallel_for_each()(見8.5.1節(jié))中使用。