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

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

2.3 轉(zhuǎn)移線(xiàn)程所有權(quán)

假設(shè)要寫(xiě)一個(gè)在后臺(tái)啟動(dòng)線(xiàn)程的函數(shù),想通過(guò)新線(xiàn)程返回的所有權(quán)去調(diào)用這個(gè)函數(shù),而不是等待線(xiàn)程結(jié)束再去調(diào)用;或完全與之相反的想法:創(chuàng)建一個(gè)線(xiàn)程,并在函數(shù)中轉(zhuǎn)移所有權(quán),都必須要等待線(xiàn)程結(jié)束??傊?,新線(xiàn)程的所有權(quán)都需要轉(zhuǎn)移。

這就是移動(dòng)引入std::thread的原因,C++標(biāo)準(zhǔn)庫(kù)中有很多資源占有(resource-owning)類(lèi)型,比如std::ifstream,std::unique_ptr還有std::thread都是可移動(dòng),但不可拷貝。這就說(shuō)明執(zhí)行線(xiàn)程的所有權(quán)可以在std::thread實(shí)例中移動(dòng),下面將展示一個(gè)例子。例子中,創(chuàng)建了兩個(gè)執(zhí)行線(xiàn)程,并且在std::thread實(shí)例之間(t1,t2和t3)轉(zhuǎn)移所有權(quán):

void some_function();
void some_other_function();
std::thread t1(some_function);            // 1
std::thread t2=std::move(t1);            // 2
t1=std::thread(some_other_function);    // 3
std::thread t3;                            // 4
t3=std::move(t2);                        // 5
t1=std::move(t3);                        // 6 賦值操作將使程序崩潰

當(dāng)顯式使用std::move()創(chuàng)建t2后②,t1的所有權(quán)就轉(zhuǎn)移給了t2。之后,t1和執(zhí)行線(xiàn)程已經(jīng)沒(méi)有關(guān)聯(lián)了;執(zhí)行some_function的函數(shù)現(xiàn)在與t2關(guān)聯(lián)。

然后,與一個(gè)臨時(shí)std::thread對(duì)象相關(guān)的線(xiàn)程啟動(dòng)了③。為什么不顯式調(diào)用std::move()轉(zhuǎn)移所有權(quán)呢?因?yàn)?,所有者是一個(gè)臨時(shí)對(duì)象——移動(dòng)操作將會(huì)隱式的調(diào)用。

t3使用默認(rèn)構(gòu)造方式創(chuàng)建④,與任何執(zhí)行線(xiàn)程都沒(méi)有關(guān)聯(lián)。調(diào)用std::move()將與t2關(guān)聯(lián)線(xiàn)程的所有權(quán)轉(zhuǎn)移到t3中⑤。因?yàn)閠2是一個(gè)命名對(duì)象,需要顯式的調(diào)用std::move()。移動(dòng)操作⑤完成后,t1與執(zhí)行some_other_function的線(xiàn)程相關(guān)聯(lián),t2與任何線(xiàn)程都無(wú)關(guān)聯(lián),t3與執(zhí)行some_function的線(xiàn)程相關(guān)聯(lián)。

最后一個(gè)移動(dòng)操作,將some_function線(xiàn)程的所有權(quán)轉(zhuǎn)移⑥給t1。不過(guò),t1已經(jīng)有了一個(gè)關(guān)聯(lián)的線(xiàn)程(執(zhí)行some_other_function的線(xiàn)程),所以這里系統(tǒng)直接調(diào)用std::terminate()終止程序繼續(xù)運(yùn)行。這樣做(不拋出異常,std::terminate()noexcept函數(shù))是為了保證與std::thread的析構(gòu)函數(shù)的行為一致。2.1.1節(jié)中,需要在線(xiàn)程對(duì)象被析構(gòu)前,顯式的等待線(xiàn)程完成,或者分離它;進(jìn)行賦值時(shí)也需要滿(mǎn)足這些條件(說(shuō)明:不能通過(guò)賦一個(gè)新值給std::thread對(duì)象的方式來(lái)"丟棄"一個(gè)線(xiàn)程)。

std::thread支持移動(dòng),就意味著線(xiàn)程的所有權(quán)可以在函數(shù)外進(jìn)行轉(zhuǎn)移,就如下面程序一樣。

清單2.5 函數(shù)返回std::thread對(duì)象

std::thread f()
{
  void some_function();
  return std::thread(some_function);
}

std::thread g()
{
  void some_other_function(int);
  std::thread t(some_other_function,42);
  return t;
}

當(dāng)所有權(quán)可以在函數(shù)內(nèi)部傳遞,就允許std::thread實(shí)例可作為參數(shù)進(jìn)行傳遞,代碼如下:

void f(std::thread t);
void g()
{
  void some_function();
  f(std::thread(some_function));
  std::thread t(some_function);
  f(std::move(t));
}

std::thread支持移動(dòng)的好處是可以創(chuàng)建thread_guard類(lèi)的實(shí)例(定義見(jiàn) 清單2.3),并且擁有其線(xiàn)程的所有權(quán)。當(dāng)thread_guard對(duì)象所持有的線(xiàn)程已經(jīng)被引用,移動(dòng)操作就可以避免很多不必要的麻煩;這意味著,當(dāng)某個(gè)對(duì)象轉(zhuǎn)移了線(xiàn)程的所有權(quán)后,它就不能對(duì)線(xiàn)程進(jìn)行加入或分離。為了確保線(xiàn)程程序退出前完成,下面的代碼里定義了scoped_thread類(lèi)?,F(xiàn)在,我們來(lái)看一下這段代碼:

清單2.6 scoped_thread的用法

class scoped_thread
{
  std::thread t;
public:
  explicit scoped_thread(std::thread t_):                 // 1
    t(std::move(t_))
  {
    if(!t.joinable())                                     // 2
      throw std::logic_error(“No thread”);
  }
  ~scoped_thread()
  {
    t.join();                                            // 3
  }
  scoped_thread(scoped_thread const&)=delete;
  scoped_thread& operator=(scoped_thread const&)=delete;
};

struct func; // 定義在清單2.1中

void f()
{
  int some_local_state;
  scoped_thread t(std::thread(func(some_local_state)));    // 4
  do_something_in_current_thread();
}                                                        // 5

與清單2.3相似,不過(guò)這里新線(xiàn)程是直接傳遞到scoped_thread中④,而非創(chuàng)建一個(gè)獨(dú)立的命名變量。當(dāng)主線(xiàn)程到達(dá)f()函數(shù)的末尾時(shí),scoped_thread對(duì)象將會(huì)銷(xiāo)毀,然后加入③到的構(gòu)造函數(shù)①創(chuàng)建的線(xiàn)程對(duì)象中去。而在清單2.3中的thread_guard類(lèi),就要在析構(gòu)的時(shí)候檢查線(xiàn)程是否"可加入"。這里把檢查放在了構(gòu)造函數(shù)中②,并且當(dāng)線(xiàn)程不可加入時(shí),拋出異常。

std::thread對(duì)象的容器,如果這個(gè)容器是移動(dòng)敏感的(比如,標(biāo)準(zhǔn)中的std::vector<>),那么移動(dòng)操作同樣適用于這些容器。了解這些后,就可以寫(xiě)出類(lèi)似清單2.7中的代碼,代碼量產(chǎn)了一些線(xiàn)程,并且等待它們結(jié)束。

清單2.7 量產(chǎn)線(xiàn)程,等待它們結(jié)束

void do_work(unsigned id);

void f()
{
  std::vector<std::thread> threads;
  for(unsigned i=0; i < 20; ++i)
  {
    threads.push_back(std::thread(do_work,i)); // 產(chǎn)生線(xiàn)程
  } 
  std::for_each(threads.begin(),threads.end(),
                  std::mem_fn(&std::thread::join)); // 對(duì)每個(gè)線(xiàn)程調(diào)用join()
}

我們經(jīng)常需要線(xiàn)程去分割一個(gè)算法的總工作量,所以在算法結(jié)束的之前,所有的線(xiàn)程必須結(jié)束。清單2.7說(shuō)明線(xiàn)程所做的工作都是獨(dú)立的,并且結(jié)果僅會(huì)受到共享數(shù)據(jù)的影響。如果f()有返回值,這個(gè)返回值就依賴(lài)于線(xiàn)程得到的結(jié)果。在寫(xiě)入返回值之前,程序會(huì)檢查使用共享數(shù)據(jù)的線(xiàn)程是否終止。操作結(jié)果在不同線(xiàn)程中轉(zhuǎn)移的替代方案,我們會(huì)在第4章中再次討論。

std::thread放入std::vector是向線(xiàn)程自動(dòng)化管理邁出的第一步:并非為這些線(xiàn)程創(chuàng)建獨(dú)立的變量,并且將他們直接加入,可以把它們當(dāng)做一個(gè)組。創(chuàng)建一組線(xiàn)程(數(shù)量在運(yùn)行時(shí)確定),可使得這一步邁的更大,而非像清單2.7那樣創(chuàng)建固定數(shù)量的線(xiàn)程。