C++11多線程互斥鎖`mutex`,`unique_lock`,`lock_guard` 條件變量

C++11多線程互斥鎖mutex,unique_lock,lock_guard

互斥鎖

??互斥鎖是線程中常用的線程同步手段, 在C++11后使用互斥互斥鎖的方式包括兩種pthread_mutex_tstd::mutex

pthread_mutex_t

這是Linux下pthread的鎖, 介紹

std::mutex

我們這里介紹一下C++11中std::mutex的基本使用

頭文件: #include<mutex>

成員函數(shù):

  • 構(gòu)造函數(shù), std::mutex _mutex;不必傳入?yún)?shù), 不允許拷貝構(gòu)造和move構(gòu)造
  • lock(): 上鎖, 如果其他線程已經(jīng)持有鎖的話會一直阻塞
  • unlock(): 解鎖
  • try_lock(): 與lock相同用于加鎖, 如果其他線程持有鎖的話立刻返回false

擴(kuò)展

??事實上還存在有其他類型的鎖, 比如:recursive_mutextime_mutex這些鎖個人基本沒用到過, 可以實現(xiàn)遞歸加鎖解鎖/加鎖超時的限制, 如果有需要自行了解

進(jìn)階版使用, unique_lock,lock_guard

對于以上的簡單使用其實與C語言相差不大, 但是我們可以使用RAII(通過類的構(gòu)造析構(gòu))來實現(xiàn)更好的編碼方式.

ps: C++相較于C引入了很多新的特性, 比如可以在代碼中拋出異常, 如果還是按照以前的加鎖解鎖的話代碼會極為復(fù)雜繁瑣

代碼:

#include <iostream>       // std::cout
#include <thread>         // std::thread
#include <mutex>          // std::mutex, std::lock_guard
#include <stdexcept>      // std::logic_error

std::mutex mtx;

void print_even (int x) {
    if (x%2==0) std::cout << x << " is even\n";
    else throw (std::logic_error("not even"));
}

void print_thread_id (int id) {
    try {
        // using a local lock_guard to lock mtx guarantees unlocking on destruction / exception:
        std::lock_guard<std::mutex> lck (mtx);
        print_even(id);
    }
    catch (std::logic_error&) {
        std::cout << "[exception caught]\n";
    }
}

int main ()
{
    std::thread threads[10];
    // spawn 10 threads:
    for (int i=0; i<10; ++i)
        threads[i] = std::thread(print_thread_id,i+1);

    for (auto& th : threads) th.join();

    return 0;
}

這里的lock_guard換成unique_lock也是一樣的, 我并未深入研究內(nèi)部實現(xiàn); 但是可以很簡單的猜到, 在構(gòu)造函數(shù)中加鎖,析構(gòu)函數(shù)中解鎖

unique_lock,lock_guard的區(qū)別

?? unique_locklock_guard都能實現(xiàn)自動加鎖和解鎖艺骂,但是前者更加靈活,能實現(xiàn)更多的功能建芙。unique_lock可以進(jìn)行臨時解鎖和再上鎖棋返,如在構(gòu)造對象之后使用lck.unlock()就可以進(jìn)行解鎖泳唠,lck.lock()進(jìn)行上鎖,而不必等到析構(gòu)時自動解鎖乙埃。

unique_lock擴(kuò)展條件變量

C++11提供std::condition_variable可以和std::mutex配合使用, 不過往往是配合unique_lock進(jìn)行使用, 所以在這里介紹一下

#include <iostream>
#include <deque>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <unistd.h>

std::deque<int> q;
std::mutex mu;
std::condition_variable cond;

void fun1() {
    while (true) {
        std::unique_lock<std::mutex> locker(mu);
        q.push_front(count);
        locker.unlock();
        cond.notify_one();  
        sleep(10);
    }
}

void fun2() {
    while (true) {
        std::unique_lock<std::mutex> locker(mu);
        cond.wait(locker, [](){return !q.empty();});
        data = q.back();
        q.pop_back();
        locker.unlock();
        std::cout << "thread2 get value form thread1: " << data << std::endl;
    }
}
int main() {
    std::thread t1(fun1);
    std::thread t2(fun2);
    t1.join();
    t2.join();
    return 0;
}

??條件變量的目的就是為了, 在沒有獲得某種提醒時長時間休眠; 如果正常情況下, 我們需要一直循環(huán)(+sleep), 這樣的問題就是CPU消耗+時延問題, 條件變量的意思是在cond.wait這里一直休眠直到cond.notify_one喚醒才開始執(zhí)行下一句; 還有cond.notify_all()接口用于喚醒所有等待的線程.

cond.wait(locker, {return !q.empty();});: 條件變量可能會被意外喚醒, 可以額外傳入一個函數(shù)只有被喚醒時同時函數(shù)返回值為true才會被真正喚醒(也可以不傳再外部判斷)

那么為什么必須使用unique_lock呢?

原因: 條件變量在wait時會進(jìn)行unlock再進(jìn)入休眠, lock_guard并無該操作接口

wait: 如果線程被喚醒或者超時那么會先進(jìn)行lock獲取鎖, 再判斷條件(傳入的參數(shù))是否成立, 如果成立則waut函數(shù)返回否則釋放鎖繼續(xù)休眠
notify: 進(jìn)行notify動作并不需要獲取鎖

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末版仔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子吨瞎,更是在濱河造成了極大的恐慌,老刑警劉巖穆咐,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颤诀,死亡現(xiàn)場離奇詭異字旭,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)崖叫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門遗淳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人心傀,你說我怎么就攤上這事屈暗。” “怎么了脂男?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵养叛,是天一觀的道長。 經(jīng)常有香客問我宰翅,道長弃甥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任汁讼,我火速辦了婚禮淆攻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嘿架。我一直安慰自己瓶珊,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布耸彪。 她就那樣靜靜地躺著伞芹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪搜囱。 梳的紋絲不亂的頭發(fā)上丑瞧,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機(jī)與錄音蜀肘,去河邊找鬼绊汹。 笑死,一個胖子當(dāng)著我的面吹牛扮宠,可吹牛的內(nèi)容都是我干的西乖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼坛增,長吁一口氣:“原來是場噩夢啊……” “哼获雕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起收捣,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤届案,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后罢艾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體楣颠,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡尽纽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了童漩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弄贿。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖矫膨,靈堂內(nèi)的尸體忽然破棺而出差凹,到底是詐尸還是另有隱情,我是刑警寧澤侧馅,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布危尿,位于F島的核電站,受9級特大地震影響施禾,放射性物質(zhì)發(fā)生泄漏脚线。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一弥搞、第九天 我趴在偏房一處隱蔽的房頂上張望邮绿。 院中可真熱鬧,春花似錦攀例、人聲如沸船逮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挖胃。三九已至,卻和暖如春梆惯,著一層夾襖步出監(jiān)牢的瞬間酱鸭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工垛吗, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留凹髓,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓怯屉,卻偏偏與公主長得像蔚舀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子锨络,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容