国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

《C++并發(fā)編程實戰(zhàn)》讀書筆記(1):線程管控

這篇具有很好參考價值的文章主要介紹了《C++并發(fā)編程實戰(zhàn)》讀書筆記(1):線程管控。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

1、線程的基本管控

包含頭文件<thread>后,通過構(gòu)建std::thread對象啟動線程,任何可調(diào)用類型都適用于std::thread

void do_some_work();

struct BackgroundTask
{
    void operator()() const;
};

//空的thread對象,不接管任何線程函數(shù)
std::thread t1;

//傳入普通函數(shù)
std::thread t2(do_some_work);

//傳入lambda函數(shù)
std::thread t3([]() { /*do something*/ });

//傳入可調(diào)用對象
BackgroundTask task;
std::thread t4(task);
//不能使用std::thread t4(BackgroundTask()),雖然本意是傳入臨時變量,但這會被編譯器解釋成函數(shù)聲明。多用一對圓括號或者使用列表初始化可以解決這個問題。
std::thread t5((BackgroundTask()));
std::thread t6{BackgroundTask()};

啟動線程后,需要明確是等待它結(jié)束、還是任由它獨自運行:

  • 調(diào)用成員函數(shù)join()會先等待線程結(jié)束,然后隸屬于該線程的任何存儲空間都會被清除,std::thread對象不再關(guān)聯(lián)到已結(jié)束的線程。
  • 調(diào)用成員函數(shù)detach()會分離線程使其在后臺運行,此后無法獲得與它關(guān)聯(lián)的std::thread對象。分離線程的歸屬權(quán)和控制權(quán)都轉(zhuǎn)移給了C++運行時庫,線程退出時與之關(guān)聯(lián)的資源會被正確回收。

調(diào)用了join()或是detach()之后,其joinable()方法將返回false,所以也就不能再調(diào)用join()。不能對空的std::thread對象調(diào)用join()或是detach()。如果線程啟動后既不調(diào)用join()也不調(diào)用detach(),那么當(dāng)std::thread對象銷毀時,其析構(gòu)函數(shù)將調(diào)用std::terminate()終止整個程序。

2、向線程函數(shù)傳遞參數(shù)

若需向線程上的函數(shù)傳遞參數(shù),直接向std::thread的構(gòu)造函數(shù)添加更多參數(shù)即可。線程具有內(nèi)部存儲空間,參數(shù)會按照默認(rèn)方式先復(fù)制到該處,然后這些副本被當(dāng)作臨時變量,以右值形式傳遞給線程上的函數(shù)。即使函數(shù)的相關(guān)參數(shù)按設(shè)想應(yīng)該是引用,上述過程依然會發(fā)生。

void f(int i, const std::string& s);
std::thread t(f, 3, "hello");

上述代碼在新線程上調(diào)用f(3, "hello"),盡管f()的第二個參數(shù)是std::string類型,但字符串內(nèi)容仍然以指針const char*的形式傳入,直到進(jìn)入新線程的上下文環(huán)境后才轉(zhuǎn)換為std::string類型。所以如果參數(shù)是指針,需要特別注意其生命周期,否則可能導(dǎo)致嚴(yán)重問題,例如:

void f(int i, const std::string& s);

void oops(int param)
{
    char buffer[1024];
    sprintf(buffer, "%d", param);
    std::thread t(f, 3, buffer);
    t.detach();
}

buffer是指向局部數(shù)組的指針,我們原本設(shè)想buffer會在新線程內(nèi)轉(zhuǎn)換成std::string對象,但在此完成之前,oops()函數(shù)很有可能已經(jīng)退出,導(dǎo)致局部數(shù)組被銷毀從而引發(fā)未定義的行為。這一問題的根源在于:std::thread的構(gòu)造函數(shù)原樣復(fù)制所提供的值,并未立即將其轉(zhuǎn)換成預(yù)期的參數(shù)類型,等到轉(zhuǎn)換發(fā)生時,指針可能已經(jīng)失效。所以解決方法就是,在buffer傳入std::thread的構(gòu)造函數(shù)之前,就先把它轉(zhuǎn)換成std::string對象:

std::thread t(f, 3, std::string(buffer));

除了指針外,傳遞引用也需要小心。例如我們想要的是非const引用:

void update_widget_data(WidgetData& data);

void oops()
{
    WidgetData data;
    std::thread t(update_widget_data, data);
    t.join();
}

根據(jù)update_widget_data函數(shù)的聲明,參數(shù)需要以引用的方式傳入,但std::thread的構(gòu)造函數(shù)對此卻毫不知情,它忽略了函數(shù)所期望的參數(shù)類型,直接復(fù)制了我們提供的值。然而,線程庫的內(nèi)部代碼會把參數(shù)的副本(std::thread構(gòu)造時由對象data復(fù)制得出,位于新線程的內(nèi)部存儲空間)以右值的形式傳遞給update_widget_data函數(shù),所以這段代碼會編譯失敗,因為不能向非const引用傳遞右值。解決方法就是使用std::ref()函數(shù)加以包裝,這樣傳遞給update_widget_data函數(shù)的就是指向data的引用,代碼就能編譯成功:

std::thread t(update_widget_data, std::ref(data));

要將某個類的成員函數(shù)設(shè)為線程函數(shù),我們需要給出合適的對象指針作為第一個參數(shù),成員函數(shù)的參數(shù)放在其后的位置。

class X
{
public:
    void do_lengthy_work();
}

X my_x;
std:thread t(&X::do_lengthy_work, &my_x);

對于只能移動、不能復(fù)制的對象,傳遞參數(shù)時需要使用std::move()來轉(zhuǎn)移歸屬權(quán)。在下面的例子中,BigObject對象的歸屬權(quán)會發(fā)生轉(zhuǎn)移,先進(jìn)入新創(chuàng)建的線程的內(nèi)部存儲空間,再轉(zhuǎn)移給process_big_object()函數(shù)。

void process_big_object(std::unique_ptr<BigObject>);

std::unique_ptr<BigObject> p(new BigObject);
std::thread t(process_big_object, std::move(p));

3、移交線程歸屬權(quán)

std::thread不能復(fù)制,但支持移動語義。對于一個具體的執(zhí)行線程,其歸屬權(quán)可以在多個std::thread實例之間轉(zhuǎn)移。

void some_function();

void some_other_function();

std::thread t1(some_function);
std::thread t2 = std::move(t1); //將線程的歸屬權(quán)顯式地轉(zhuǎn)移給t2
t1 = std::thread(some_other_function); //線程原本與std::thread臨時對象關(guān)聯(lián),其歸屬權(quán)隨即轉(zhuǎn)移給t1
std::thread t3; //按默認(rèn)方式構(gòu)造,未關(guān)聯(lián)任何線程
t3 = std::move(t2); //t2原本關(guān)聯(lián)的線程的歸屬權(quán)轉(zhuǎn)移給t3
//經(jīng)過上面這些轉(zhuǎn)移,t1與運行some_other_function的線程關(guān)聯(lián),t2沒有關(guān)聯(lián)線程,t3與運行some_function的線程關(guān)聯(lián)

t1 = std::move(t3); //在這次轉(zhuǎn)移之時,t1已經(jīng)關(guān)聯(lián)運行some_other_function的線程,因此std::thread的析構(gòu)函數(shù)中會調(diào)用std::terminate(),終止整個程序。所以只要std::thread對象還在管控著一個線程,就不能簡單地向它賦新值。

因為std::thread支持移動語義,所以只要容器同樣知悉移動意圖,就可以裝載std::thread對象。因此我們可以寫出下列代碼,生成多個線程,然后等待它們運行完成。

void do_work(unsigned id);

void foo()
{
    std::vector<std::thread> threads;
    for (unsigned i = 0; i < 20; ++i)
    {
        threads.push_back(std::thread(do_work, i));
    }
    for (auto& entry : threads)
    {
        entry.join();
    }
}

4、識別線程

使用C++標(biāo)準(zhǔn)庫的std::thread::hardware_concurrency()函數(shù)可以獲取系統(tǒng)中邏輯處理器的數(shù)量。如果信息無法獲取,該函數(shù)可能返回0。

線程ID的類型是std::thread::id,它有兩種獲取方法:

  • 在與線程關(guān)聯(lián)的std::thread對象上調(diào)用成員函數(shù)get_id(),即可得到該線程的ID。如果std::thread對象沒有關(guān)聯(lián)任何執(zhí)行線程,則調(diào)用get_id()返回的是按默認(rèn)構(gòu)造方式生成的std::thread::id對象,表示“線程不存在”。
  • 當(dāng)前線程的ID可以通過調(diào)用std::this_thread::get_id()獲取。

std::thread::id對象可以支持很多種操作:文章來源地址http://www.zghlxwxcb.cn/news/detail-689474.html

  • 可隨意進(jìn)行復(fù)制操作或比較運算。
  • 可用作關(guān)聯(lián)容器(std::set、std::map、std::multiset、std::multimap)的鍵值,無序關(guān)聯(lián)容器(std::unordered_set、std::unordered_map、std::unordered_multiset、std::unordered_multimap)的鍵值,或用于排序。
  • 寫到輸出流,例如std::cout << std::this_thread::get_id();。

到了這里,關(guān)于《C++并發(fā)編程實戰(zhàn)》讀書筆記(1):線程管控的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 并發(fā)編程: 2. 線程管控

    給定一個線程,只要令std::thread對象與之關(guān)聯(lián),就能管控該線程的幾乎每個細(xì)節(jié)。 2.1.1 發(fā)起線程 線程通過構(gòu)建std::thread對象而啟動,該對象指明線程要運行的任務(wù)(函數(shù))。簡單的任務(wù),函數(shù)結(jié)束返回,線程隨即終止。復(fù)雜的任務(wù)情況下,函數(shù)可以由函數(shù)對象表示,還接受參

    2024年02月05日
    瀏覽(21)
  • c++并發(fā)編程實戰(zhàn)-第3章 在線程間共享數(shù)據(jù)

    多線程之間共享數(shù)據(jù),最大的問題便是數(shù)據(jù)競爭導(dǎo)致的異常問題。多個線程操作同一塊資源,如果不做任何限制,那么一定會發(fā)生錯誤。例如: 輸出: 顯然,上面的輸出結(jié)果存在問題。出現(xiàn)錯誤的原因可能是: 某一時刻, th1線程獲得CPU時間片,將g_nResource從100增加至200后時

    2024年02月08日
    瀏覽(14)
  • java并發(fā)編程之美第五章讀書筆記

    java并發(fā)編程之美第五章讀書筆記

    CopyOnWriteArrayList 線程安全的ArrayList,對其進(jìn)行的修改操作都是在底層的一個復(fù)制的數(shù)組(快照)進(jìn)行的,也就是寫時復(fù)制策略 類圖 每一個對象里面有一個array數(shù)組進(jìn)行存放具體的元素,ReentrantLock獨占鎖對象用來保證同時只有一個線程對array進(jìn)行修改,這里只要記得ReentrantLock是獨占鎖

    2024年02月03日
    瀏覽(20)
  • C++線程入門:輕松并發(fā)編程

    ????????在現(xiàn)代計算機(jī)應(yīng)用程序中,我們經(jīng)常需要處理并發(fā)任務(wù),這就需要使用多線程來實現(xiàn)。C++是一種功能強(qiáng)大的編程語言,提供了豐富的線程支持,使得并發(fā)編程變得相對容易。 ????????C++ 線程是一種多線程編程模型,可以在同一個程序中同時執(zhí)行多個獨立的任務(wù)

    2024年02月04日
    瀏覽(21)
  • 《C++高級編程》讀書筆記(七:內(nèi)存管理)

    《C++高級編程》讀書筆記(七:內(nèi)存管理)

    1、參考引用 C++高級編程(第4版,C++17標(biāo)準(zhǔn))馬克·葛瑞格爾 2、建議先看《21天學(xué)通C++》 這本書入門,筆記鏈接如下 21天學(xué)通C++讀書筆記(文章鏈接匯總) 1. 使用動態(tài)內(nèi)存 1.1 如何描繪內(nèi)存 在本書中,內(nèi)存單元表示為一個帶有標(biāo)簽的框,該標(biāo)簽表示這個內(nèi)存對應(yīng)的變量名,方

    2024年02月08日
    瀏覽(57)
  • JUC并發(fā)編程學(xué)習(xí)筆記(十)線程池(重點)

    JUC并發(fā)編程學(xué)習(xí)筆記(十)線程池(重點)

    線程池:三大方法、七大參數(shù)、四種拒絕策略 池化技術(shù) 程序的運行,本質(zhì):占用系統(tǒng)的資源!優(yōu)化資源的使用!- 池化技術(shù)(線程池、連接池、對象池......);創(chuàng)建和銷毀十分消耗資源 池化技術(shù):事先準(zhǔn)備好一些資源,有人要用就拿,拿完用完還給我。 線程池的好處: 1、

    2024年02月06日
    瀏覽(30)
  • JUC并發(fā)編程學(xué)習(xí)筆記(一)認(rèn)知進(jìn)程和線程

    進(jìn)程 一個程序,如QQ.exe,是程序的集合 一個進(jìn)程往往可以包含多個線程,至少包含一個 java默認(rèn)有兩個線程,GC垃圾回收線程和Main線程 線程:一個進(jìn)程中的各個功能 java無法真正的開啟線程,因為java是運行在虛擬機(jī)上的,所以只能通過C++,通過native本地方法調(diào)用C++開啟線程

    2024年02月06日
    瀏覽(95)
  • Java并發(fā)編程學(xué)習(xí)筆記(一)線程的入門與創(chuàng)建

    Java并發(fā)編程學(xué)習(xí)筆記(一)線程的入門與創(chuàng)建

    認(rèn)識 程序由指令和數(shù)據(jù)組成,簡單來說,進(jìn)程可以視為程序的一個實例 大部分程序可以同時運行多個實例進(jìn)程,例如記事本、畫圖、瀏覽器等 少部分程序只能同時運行一個實例進(jìn)程,例如QQ音樂、網(wǎng)易云音樂等 一個進(jìn)程可以分為多個線程,線程為最小調(diào)度單位,進(jìn)程則是作

    2024年02月16日
    瀏覽(46)
  • c++并發(fā)編程實戰(zhàn)-第4章 并發(fā)操作的同步

    c++并發(fā)編程實戰(zhàn)-第4章 并發(fā)操作的同步

    想象一種情況:假設(shè)晚上坐車外出,如何才能確保不坐過站又能使自己最輕松? 這種方式存在雙重浪費: 線程 th1(wait_for_flag)須不斷查驗標(biāo)志,浪費原本有用的處理時間,這部分計算資源原本可以留給其他線程使用。 線程 th1(wait_for_flag)每次循環(huán)都需要給互斥上鎖,導(dǎo)致

    2024年02月08日
    瀏覽(19)
  • 《Java并發(fā)編程實戰(zhàn)》課程筆記(二)

    《Java并發(fā)編程實戰(zhàn)》課程筆記(二)

    在單核時代,所有的線程都是在一顆 CPU 上執(zhí)行,CPU 緩存與內(nèi)存的數(shù)據(jù)一致性容易解決。 因為所有線程都是操作同一個 CPU 的緩存,一個線程對緩存的寫,對另外一個線程來說一定是可見的。 一個線程對共享變量的修改,另外一個線程能夠立刻看到,我們稱為可見性。 多核

    2024年02月06日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包