最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++中多線程間共享數(shù)據(jù)詳解

 更新時間:2024年01月09日 11:03:21   作者:wingのpeterPen  
這篇文章主要為大家詳細介紹了C++中多線程間共享數(shù)據(jù)的相關(guān)知識,文中的示例代碼講解詳細,具有一定的借鑒價值,感興趣的小伙伴可以跟隨小編一起學(xué)習一下

在 C++ 中,我們可以通過構(gòu)造 std::mutex (mutual exclusion)的實例來創(chuàng)建互斥,調(diào)用成員函數(shù) lock() 對其加鎖,調(diào)用 unlock() 解鎖。但是不推薦直接調(diào)用成員函數(shù)的做法,因為這樣做,那我們就必須在該函數(shù)的每條路徑上都調(diào)用 unlock(),包括異常導(dǎo)致退出的路徑。取而代之,C++標準庫提供了類模板 std::lock_guard<>,針對互斥類融合RAII手法:在構(gòu)造的時候給互斥加鎖,在析構(gòu)時進行解鎖,從而保證互斥總被正確解鎖。

std::mutex的基本用法

std::list<int> some_list;
std::mutex some_mutex;

void add_to_list(int new_value){
    std::lock_guard<std::mutex> guard(some_mutex);
	some_list.push_back(new_value);
}

bool list_contains(int value_to_find){
    std::lock_guard<std::mutex> guard(some_mutex);
    return std::find(some_list.begin(), some_list.end(), value_to_find) != some_list.end();
}

防范死鎖

防范死鎖的通常建議是,始終按相同順序?qū)蓚€互斥加鎖。若我們總是先鎖互斥A,再鎖互斥B,則永遠不會發(fā)生死鎖。但是有時會出現(xiàn)一些棘手的問題,例如,一個函數(shù),其操作同一個類的兩個實例,交換它們內(nèi)部的數(shù)據(jù)為了保證并發(fā)時,免受其他改動的影響,需要對它們進行加鎖,但是函數(shù)入?yún)⒌捻樞蚩梢愿淖?,即可以是swap(A,B)也可以是swap(B,A),當同時發(fā)生這種情況時,死鎖也會發(fā)生。因此需要一種方式來,來同時鎖住兩個互斥,而不是誰先誰后。即要求“全員共同成敗”(all-or-nothing,或全部成功鎖定,或沒獲取任何鎖并拋出異常)的語義。

使用 std::lock() 函數(shù),同時鎖住互斥。

class some_big_object;
void swap(some_big_object& lhs, some_big_object& rhs);

class X{
private:
	some_big_object some_detail;
	std::mutex m;

public:
	X(const some_big_object &sd):some_detail(sd){}

	friend void swap(X& lhs, X& rhs){
        if(&lhs == &rhs){
            return;
        }

        std::lock(lhs.m, rhs.m);
        std::lock_guard lock_a(lhs.m, std::adopt_lock);
        std::lock_guard lock_b(rhs.m, std::adopt_lock);

        swap(lhs.some_detail, rhs.some_detail);
    }
}

std::lock() 是一個函數(shù),并不像 RAII 類一樣,在析構(gòu)時進行解鎖。因此需要借助 std::lock_guard 類型的對象,讓 std::mutex 在函數(shù)完成后進行解鎖。std::adopt_lock 作為函數(shù)參數(shù),表示 std::mutex 已經(jīng)被鎖住了,讓std::lock_guard 類不需要在構(gòu)造函數(shù)中對 std::mutex 進行加鎖。C++ 17出現(xiàn)了 std::scoped_lock<> 模板類,其和 std::lock_guard<>完全等價,只不過前者是可變參數(shù)模板,接受各種互斥型別作為模板參數(shù),還以多個互斥對象作為構(gòu)造函數(shù)的參數(shù)列表,除了這些其還有與 std::lock() 函數(shù)一樣的功能,因此可以改善上述代碼。

void swap(X& lhs, X& rhs){
    if(&lhs == &rhs){
            return;
    }

    std::scoped_lock guard(lhs.m, rhs.m);
    swap(lhs.some_detail, rhs.some_detail);
}

std::lock_guard 和 std::unique_lock

std::unique_lock 類支持在構(gòu)造時暫時不獲得鎖,在需要的時候手動調(diào)用 lock(),而獲得鎖。其含有一個內(nèi)部標志 __owns__(可以通過其成員函數(shù) owns_lock() 獲得),表明關(guān)聯(lián)的互斥目前是否正被該類的實例上鎖。假如 std::unique_lock 實例關(guān)聯(lián)的互斥的確上鎖了,則其析構(gòu)函數(shù)必須調(diào)用unlock();若不然,實例并未將關(guān)聯(lián)的互斥上鎖,便絕不能調(diào)用 unlock()。

初始化時保護共享數(shù)據(jù)

void undefined_behaviour_with_double_checked_locking()
{
    if(!resource_ptr){ //①
        std::lock_guard<std::mutex> lk(resource_mutex); // ②
        if(!resource_ptr){
            resource_ptr.reset(new some_resource);
        }
    }
    resource_ptr->do_something();
}

在雙重檢查鎖定模式中,一號線程執(zhí)行到①發(fā)現(xiàn)條件滿足(resource_ptr 為空),同時二號線程執(zhí)行到①也發(fā)現(xiàn)條件滿足,然后繼續(xù)執(zhí)行上鎖操作②,此時一號線程也會去執(zhí)行上鎖操作,但是resource_mutex上的鎖已經(jīng)被二號線程持有了,這樣就會發(fā)生數(shù)據(jù)競爭(當然會發(fā)生惡性數(shù)據(jù)競爭的路徑不止這一條)。

為了解決這種情況,C++標準庫中提供了 std::onec_flag 類 和 std::call_once 類。

std::shared_ptr<some_resource> resource_ptr;
std::once_flag resource_flag;

void init_resource()
{
    resource_ptr.reset(new some_resource);
}

void foo()
{
    std::call_once(resource_flag, init_resource);
    resource_ptr->do_something();
}

保護讀多寫少的數(shù)據(jù)

C++ 17 標準庫提供了兩種新的互斥:std::shared_mutex 和 std::shared_timed_mutex(C++14就有了)。兩者的區(qū)別在于后者支持更多操作。

std::shared_mutex mutex;

// 獲取讀鎖(又叫共享鎖)
std::shared_lock read_lock(mutex);

// 獲取寫鎖(又叫排它鎖)
std::lock_guard write_lock(mutex);

假設(shè)共享鎖已經(jīng)被某些線程持有,若別的線程試圖獲取排他鎖,就會發(fā)生阻塞,直到這些線程全都釋放該共享鎖。反之,如果任一線程持有排他鎖,那么其他線程都無法獲取共享鎖或排它鎖,直到持鎖線程將排它鎖釋放為止。

到此這篇關(guān)于C++中多線程間共享數(shù)據(jù)詳解的文章就介紹到這了,更多相關(guān)C++共享數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言中單目操作符++、–的實例講解

    C語言中單目操作符++、–的實例講解

    C語言的操作符共分為算術(shù)操作符,移位操作符,位操作符,賦值操作符,單目操作符,關(guān)系操作符,邏輯操作符,條件操作符,逗號表達式,下表引用、函數(shù)調(diào)用和結(jié)構(gòu)成員這10大類,這篇文章主要給大家介紹了關(guān)于C語言中單目操作符++、–的相關(guān)資料,需要的朋友可以參考下
    2021-12-12
  • C++ Boost TypeTraits庫使用詳解

    C++ Boost TypeTraits庫使用詳解

    Boost是為C++語言標準庫提供擴展的一些C++程序庫的總稱。Boost庫是一個可移植、提供源代碼的C++庫,作為標準庫的后備,是C++標準化進程的開發(fā)引擎之一,是為C++語言標準庫提供擴展的一些C++程序庫的總稱
    2022-11-11
  • C語言編程C++動態(tài)內(nèi)存分配示例講解

    C語言編程C++動態(tài)內(nèi)存分配示例講解

    這篇文章主要介紹了C語言編程C++動態(tài)內(nèi)存分配示例講解,為什么存在動態(tài)內(nèi)存分配?本文通過動態(tài)內(nèi)存介紹及常見內(nèi)存錯誤等示例來為大家講解
    2021-09-09
  • C語言指針入門學(xué)習面面觀

    C語言指針入門學(xué)習面面觀

    這篇文章主要介紹了C語言指針的一些基礎(chǔ)知識,指針可以說是C語言入門學(xué)習中的頭等大事,文中從數(shù)組和函數(shù)等多方面剖析C中指針的作用,需要的朋友可以參考下
    2016-02-02
  • MinGW-w64 C/C++編譯器下載和安裝的方法步驟(入門教程)

    MinGW-w64 C/C++編譯器下載和安裝的方法步驟(入門教程)

    如果電腦沒有安裝MinGW-w64 C/C++編譯器,就無法運行g(shù)cc命令,本文主要介紹了MinGW-w64 C/C++編譯器下載和安裝的方法步驟,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • C++成員函數(shù)中const的使用詳解

    C++成員函數(shù)中const的使用詳解

    這篇文章主要為大家詳細介紹了C++成員函數(shù)中const的使用,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • C++發(fā)郵件簡單實例詳解

    C++發(fā)郵件簡單實例詳解

    這篇文章主要為大家詳細介紹了C++發(fā)郵件的簡單實例,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • 如何用矩形法(梯形法)求定積分

    如何用矩形法(梯形法)求定積分

    思路就是將積分區(qū)間劃分成n等份,然后將這n等份近似看成矩形(或梯形),然后對所有的矩形(或梯形)的面積進行求和
    2013-09-09
  • VS2019配置BOOST的方法(v1.70.0庫)

    VS2019配置BOOST的方法(v1.70.0庫)

    這篇文章主要介紹了VS2019配置BOOST的方法(v1.70.0庫),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧
    2020-08-08
  • C# 使用反射來實現(xiàn)對象的深度復(fù)制方法

    C# 使用反射來實現(xiàn)對象的深度復(fù)制方法

    下面小編就為大家?guī)硪黄狢# 使用反射來實現(xiàn)對象的深度復(fù)制方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01

最新評論

类乌齐县| 光泽县| 大连市| 准格尔旗| 南宫市| 新干县| 龙江县| 铜山县| 昌图县| 东城区| 南部县| 论坛| 新干县| 革吉县| 金坛市| 托克托县| 循化| 田阳县| 天气| 广安市| 枣强县| 东兴市| 电白县| 军事| 锡林浩特市| 凤庆县| 宁城县| 孝昌县| 上栗县| 太保市| 乌兰县| 永嘉县| 琼结县| 荃湾区| 宜城市| 博客| 延寿县| 英德市| 盐源县| 塔城市| 焦作市|