關於std::thread以及std::condition_variable的一些細節備忘

來源:互聯網
上載者:User

標籤:+=   forward   get   break   函數調用   rom   細節   程式   個人   

  也算是看過不少多線程相關的資料了,但是一直對於其中的一些細節沒有太好的把握,比如std::thread線程真正開始啟動並執行時機,比如join、detch等真正的作用。

跟著《Cplusplus Concurrency In Action_Practical Multithreading》又過了一遍相關的細節,下面記錄一下一些個人所獲得的收穫。

std::thread真正開始啟動並執行時機

下面是我嘗試寫的一個基於條件變數和互斥量的生產者消費者模型的Demo,就從這裡開始說起

#include<iostream>#include<thread>#include<unistd.h>#include<vector>#include<mutex>#include<condition_variable>#include<cmath>std::vector<int> resource;std::mutex m;std::condition_variable cv;void thread_procedure(){    while(true){        int n;        while(true){            std::unique_lock<std::mutex> ul(m);            cv.wait(ul,[&]{return !resource.empty();});            if(!resource.empty()) {                n = resource.back();                resource.pop_back();                break;            }        }        int res = 0;        for(int i = 0; i<n; ++i){            //sleep(2);            res+=i;        }        std::lock_guard<std::mutex> ll(m);        std::cout<<"This is from Thread "<<std::this_thread::get_id()<<", "<<"The sum of 0+1+2+...+"<<n<<" is "<<res<<std::endl;    }}int main(){    std::thread tt[5];    for(int i = 0; i<5; ++i){        tt[i] = std::thread(thread_procedure);    }        for(int i = 0; i<5; ++i){        tt[i].join();    }    while(true){        std::lock_guard<std::mutex> lg(m);        resource.push_back(rand()%100);        cv.notify_one();    }}

這段代碼使用了一個std::mutex和一個std::condition_variable控制相應的線程,嘗試實現一個簡單的列印功能。

但在運行時該代碼會卡在生產者處,即join代碼之後的while迴圈不會運行下去。。。

這裡幾乎就涉及了std::thread線程庫裡面對於線程啟動的機制以及join的真正語義了。

下面是一段GNU對於std::thread的實現代碼:

class thread{    ...public:    thread() noexcept = default;    thread(thread&) = delete;    thread(const thread&) = delete;    thread(thread&& __t) noexcept    { swap(__t); }    template<typename _Callable, typename... _Args>    explicit thread(_Callable&& __f, _Args&&... __args)    {        _M_start_thread(_M_make_routine(std::__bind_simple(        std::forward<_Callable>(__f),        std::forward<_Args>(__args)...)));     }    ...};

可以看到thread的建構函式傳入了一個_Callable可調用對象以及相關的參數,然後使用了std::__bind_simple進行了封裝,相當於std::bind,然後使用_M_start_thread直接使用平台相關線程實現開啟了這個線程!

從這裡我們可以看出在每個std::thread構造完成的時候新線程就已經開啟了!

而join函數的作用就是等待join的線程執行結束,在join返回之後繼續運行後續代碼。

這樣上面的代碼會卡住也就理所應當了,在開啟新線程之後資源集區就用完了,然後啟動的線程都阻塞在條件變數上面,而後續的while迴圈裡面的生產過程則是由於join函數在等待已經開啟的線程結束而無法運行。

整個程式就會在所有線程都處於阻塞狀態下停在那裡。

而解決這個問題的方法倒也簡單,另開一個生產者線程就行,如下代碼:

#include<iostream>#include<thread>#include<unistd.h>#include<vector>#include<mutex>#include<condition_variable>#include<cmath>std::vector<int> resource;std::mutex m;std::condition_variable cv;void thread_procedure(){    while(true){        int n;        while(true){            std::unique_lock<std::mutex> ul(m);            cv.wait(ul,[&]{return !resource.empty();});            if(!resource.empty()) {                n = resource.back();                resource.pop_back();                break;            }        }        int res = 0;        for(int i = 0; i<n; ++i){            res+=i;        }        std::lock_guard<std::mutex> ll(m);        std::cout<<"This is from Thread "<<std::this_thread::get_id()<<", "<<"The sum of 0+1+2+...+"<<n<<" is "<<res<<std::endl;    }}void producer(){    while(true){        std::lock_guard<std::mutex> lg(m);        resource.push_back(rand()%100);        cv.notify_one();    }}int main(){    std::thread tt[6];    for(int i = 0; i<5; ++i){        tt[i] = std::thread(thread_procedure);    }        tt[5] = std::thread(producer);        for(int i = 0; i<6; ++i){        tt[i].join();    }}

這種情況下,所有背景工作執行緒都在join函數調用之前就開啟了,也就不會存在上述問題了。

關於std::thread以及std::condition_variable的一些細節備忘

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.