c++併發編程之thread::join()和thread::detach()

c++併發編程之thread::join()和thread::detach()

thread::join(): 阻塞當前線程,直至 *this 所標識的線程完成其執行。*this 所標識的線程的完成同步於從 join() 的成功返回。html

該方法簡單暴力,主線程等待子進程期間什麼都不能作。thread::join()會清理子線程相關的內存空間,此後thread object將再也不和這個子線程相關了,即thread object再也不joinable了,因此join對於一個子線程來講只能夠被調用一次,爲了實現更精細的線程等待機制,能夠使用條件變量等機制。ios

複製代碼

#include <iostream>
#include <thread>
#include <chrono>
 
void foo()
{
    std::cout << "foo is started\n";
    // 模擬昂貴操做
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "foo is done\n";
}
 
void bar()
{
    std::cout << "bar is started\n";
    // 模擬昂貴操做
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "bar is done\n";
}
 
int main()
{
    std::cout << "starting first helper...\n";
    std::thread helper1(foo);
 
    std::cout << "starting second helper...\n";
    std::thread helper2(bar);
 
    std::cout << "waiting for helpers to finish...\n" << std::endl;
    helper1.join();
    helper2.join();
 
    std::cout << "done!\n";
}

複製代碼

運行結果:c++

複製代碼

starting first helper...
starting second helper...
foo is started
waiting for helpers to finish...
bar is started

foo is done
bar is done
done!

複製代碼

 異常環境下join,假設主線程在一個函數f()裏面建立thread object,接着f()又調用其它函數g(),那麼確保在g()以任何方式下退出主線程都能join子線程。如:若g()經過異常退出,那麼f()須要捕捉異常後join.編程

複製代碼

#include<iostream>  
#include<boost/thread.hpp>  
void do_something(int& i){  
    i++;  
}  
class func{  
    public:  
        func(int& i):i_(i){}  
        void operator() (){  
            for(int j=0;j<100;j++)  
                do_something(i_);  
        }  
    public:  
        int& i_;  
};  
void do_something_in_current_thread(){}  
void f(){  
    int local=0;  
    func my_func(local);  
    boost::thread t(my_func);  
    try{  
        do_something_in_current_thread();  
    }  
    catch(...){  
        t.join();//確保在異常條件下join子線程  
        throw;  
    }  
    t.join();  
}  
int main(){  
    f();  
    return 0;  
}

複製代碼

上面的方法看起來笨重,有個解決辦法是採用RAII(資源獲取即初始化),將一個thread object經過棧對象A管理,在棧對象A析構時調用thread::join.按照局部對象析構是構造的逆序,棧對象A析構完成後再析構thread object。以下:併發

複製代碼

#include<iostream>  
#include<boost/noncopyable.hpp>  
#include<boost/thread.hpp>  
using namespace std;  
class thread_guard:boost::noncopyable{  
    public:  
        explicit thread_guard(boost::thread& t):t_(t){}  
        ~thread_guard(){  
            if(t_.joinable()){//檢測是頗有必要的,由於thread::join只能調用一次,要防止其它地方意外join了  
               t_.join();  
            }  
        }  
        //thread_guard(const thread_guard&)=delete;//c++11中這樣聲明表示禁用copy constructor須要-std=c++0x支持,這裏採用boost::noncopyable已經禁止了拷貝和複製  
        //thread_guard& operator=(const thread_guard&)=delete;  
    private:  
        boost::thread& t_;  
};  
void do_something(int& i){  
    i++;  
}  
class func{  
    public:  
        func(int& i):i_(i){}  
        void operator()(){  
            for(int j=0;j<100;j++)  
                do_something(i_);  
        }  
    public:  
        int& i_;  
};  
void do_something_in_current_thread(){}  
void fun(){  
    int local=0;  
    func my_func(local);  
    boost::thread t(my_func);  
    thread_guard g(t);  
    do_something_in_current_thread();  
}  
int main(){  
    fun();  
    return 0;  
}

複製代碼

 

thread::detach(): 從 thread 對象分離執行的線程,容許執行獨立地持續。一旦線程退出,則釋放全部分配的資源。調用 detach 後, *this 再也不佔有任何線程。函數

複製代碼

#include <iostream>
#include <chrono>
#include <thread>
 
void independentThread() 
{
    std::cout << "Starting concurrent thread.\n";
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "Exiting concurrent thread.\n";
}
 
void threadCaller() 
{
    std::cout << "Starting thread caller.\n";
    std::thread t(independentThread);
    t.detach();
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Exiting thread caller.\n";
}
 
int main() 
{
    threadCaller();
    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "back to main.\n";
}

複製代碼

運行結果:this

Starting thread caller.
Starting concurrent thread.
Exiting thread caller.
Exiting concurrent thread.
back to main.

 若是註釋掉main函數裏的std::this_thread::sleep_for(std::chrono::seconds(5)); 即不等待independentThread 執行完。運行結果以下:spa

Starting thread caller.
Starting concurrent thread.
Exiting thread caller.
back to main.
相關文章
相關標籤/搜索