detach()的坑 ,注意點,傳遞類對象、智能指針、成員函數作爲線程函數

void myprint(const int i,const string &pmybuf)
{
    cout<<i<<endl;//分析發現i並不是mvar的引用,而是值傳遞。但是並不推薦這麼使用
    cout<<pmybuf.c_str()<<endl;//指針在detach子線程時,絕對會有問題。
    return ;
}
int main()
{
    //傳遞臨時對象作爲線程參數
    int mvar =1;
    int &myvar=mvar;
    char buf[]="this a test!";
    第一個參數是函數名,從後面開始就是傳入這個線程函數的參數
    thread my_th(myprint,mvar,buf);
    buf是在什麼時候轉換成string的?
    事實上存在,buf的內存被回收了,系統才用buf去轉成string。
    //my_th.join();
    my_th.detach();//主線程退出,mvar在子線程中會不會出問題?
    cout<<"I LOve CHNIA"<<endl;
    return 0;
}
將上面的代碼換成這個就不會有問題
thread my_th(myprint,mvar,string(buf));//生成一個臨時string對象它會綁定到
這裏將buf轉換成string對象,這是一個可以保證在線程中安全的方法。

thread my_th(myprint,mvar,A(a));


class A{
    public:
    int m_i;
    A(int a):m_i(a){cout<<"構造函數。。。"<<std::this_thread::get_id()<<endl;}
    A(const A &a):a.m_i{cout<<"拷貝構造函數。。。"<<std::this_thread::get_id()<<endl;}
    ~A()cout<<"析構函數。。。"<<std::this_thread::get_id()<<endl;}
};

int main()
{
    int a=1;
    int vara=12;
    thread my_th(myprint,mvar,A(vara));
    
    
    cout<<"I LOve CHNIA"<<endl;
    return 0;
    
}

總結:
1、如果傳遞int這種簡單的參數類型,建議使用值傳遞,不要使用引用。/2、如果傳遞類對象,避免隱式類型轉換,全部都在創建線程這一行就構建臨時對象,然後在函數參數裏使用引用來接,否則系統還會多構造一次對象。
建議不使用detach(),只是有jion()。

線程id的概念:
id是一個數字:每個線程,都對應一個線程id,都不同。
c++函數庫裏面的函數來獲取 std::this_thread::get_id()來獲取。

 

使用類對象創建線程

class A{
public:
    mutable int m_i;
	A(int a):m_i(a){cout<<"構造函數"<<std::this_thread::get_id()<<endl;}
	A(const A &a):m_i(a.m_i){cout<<"拷貝構造函數"<<endl;}
	~A(){cout<<"析構函數"<<std::this_thread::get_id()<<endl;}
    void print(const A &buf)
    {
        buf.m_i =199;//修改值不會影響main函數
		cout<<"子線程的參數地址:"<<&buf<<"threadID:"<<std::this_thread::get_id()<<endl;

    }
//std::ref向線程中傳遞類對象,編譯器都會安裝
};

int main()
{
   A myobj(10);
   std::thread myth(print,myobj);//將類對象作爲線程的參數,會調用到對象拷貝構造函數
   向線程中傳遞類對象,編譯器都會按照拷貝的方式傳入
   如果想傳遞進去的是引用,而不是拷貝,則需要使用std::ref
   //std::thread myth(print,std::ref(myobj));這樣傳遞的就是真的引用,真的會改變這個值,不能使用detach()
   myth(print,&myobj);這樣傳遞的就是真的引用,真的會改變這個值,不能使用detach()
   myth.join();
   
   return 0;
}

-----------------------------


    void print(unique_ptr<int> x)
    {
        
		cout<<"子線程的參數地址:"<<&buf<<"threadID:"<<std::this_thread::get_id()<<endl;

    }
	
    int main()
    {
        unique_ptr<int> p_int(new int(100));//獨佔方式指針
        std::thread myth(print,std::move(p_int));//修改佔方式指針使用std::move()
        myth.join();//在這種情況下,千萬不能detach(),不然線程不安全。
        return 0;
    }

----------------------------------------------------------
class A{
public:
    
	A(int a):m_i(a){cout<<"構造函數"<<std::this_thread::get_id()<<endl;}
	A(const A &a):m_i(a.m_i){cout<<"拷貝構造函數"<<endl;}
	~A(){cout<<"析構函數"<<std::this_thread::get_id()<<endl;}
    void thread_work(int num)
   {
	   cout<<"子線程執行了:"<<this<<"threadID = "<<std::this_thread::get_id()<<endl;
	
   }
   
   int m_i;

};

int main()
{
   A myobj(10);//生成一個類對象
   std::thread myth(&A::thread_work,myobj,15);
   //這邊的myobj放入子線程會調用拷貝構造函數
   myth.join();
   
   return 0;
}


----------------------------------------------------------
class A{
public:
    
	A(int a):m_i(a){cout<<"構造函數"<<std::this_thread::get_id()<<endl;}
	A(const A &a):m_i(a.m_i){cout<<"拷貝構造函數"<<endl;}
	~A(){cout<<"析構函數"<<std::this_thread::get_id()<<endl;}
    void operator(int num)
   {
	   cout<<"子線程()執行了:"<<this<<"threadID = "<<std::this_thread::get_id()<<endl;
	
   }
   
   int m_i;

};

int main()
{
   A myobj(10);//生成一個類對象
   std::thread myth(myobj,15);//這邊的myobj放入子線程會調用拷貝構造函數,複製出一個對象。
   
   
   myth.join();
   
   return 0;
}

 

發佈了92 篇原創文章 · 獲贊 71 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章