C++11スレッドオブジェクトthread

30100 ワード

文書ディレクトリ
  • スレッド起動:threadオブジェクト構築関数
  • グローバル関数による
  • の構築
  • lamda式により
  • を構築する.
  • 関数オブジェクトによる
  • の構築
  • メンバー関数による
  • の構築
  • スレッド終了
  • 加入式:join()
  • 分離式:detach()
  • スレッドセキュアthread
  • threadオブジェクトは、所有権
  • を移行することができる.
  • インテリジェントポインタ管理threadオブジェクト
  • スレッドクラスthreadは、RAIDスレッドの作成と破棄を提供します.スレッドの作成時にスレッドが実行するコードセグメント(関数、lamda式)とパラメータが入力され、thread構造関数はスレッドを自動的に破棄します.
  • C++スレッドライブラリは、スレッド関数、スレッドスタック、スレッド開始状態など、スレッドIDなど、スレッド実行時のコンテキスト環境を含むスレッドオブジェクトを構築することによって、すべての操作がカプセル化され、最後に下位層で統一的に_beginthreadex()はスレッド関数を作成して実現します(注意:_beginthreadexはwindowsでスレッドを作成する最下位のc関数です).
  • std::thread()新しいスレッドを作成すると、lambda式(変数取得または非帯域)、関数(グローバル関数またはメンバー関数)、関数オブジェクトを含む任意の呼び出し可能なオブジェクトタイプ(パラメータ付きまたはパラメータなし)を受け入れることができます.

  • スレッド起動:threadオブジェクト構築関数
    グローバル関数による構築
    #include
    #include
    using std::cout;
    using std::endl;
    void threadRoute(int a,int b)
    {
    	cout << "I am a new thread of " << std::this_thread::get_id() << endl;
    	cout << a + b << endl;
    }
    int main()
    {
    	int a = 10, b = 20;
    	cout << "I am the main thread,and my thread id is " << std::this_thread::get_id() << endl;
    	std::thread t(threadRoute,a,b);//thread              
    	t.join();//    ,        
    	system("pause");
    }
    

    lamda式で構築
    #include
    #include
    
    using std::cout;
    using std::endl;
    
    int main()
    {
    	int a = 10, b = 20;
    	cout << "I am the main thread,and my thread id is " << std::this_thread::get_id() << endl;
    	std::thread t([=]{
    		cout << "I am a new thread of " << std::this_thread::get_id() << endl;
    		cout << a + b << endl;
    	});
    	t.join();//    ,        
    	system("pause");
    }
    

    関数オブジェクトによる構築
    #include
    #include
    
    using std::cout;
    using std::endl;
    
    struct funcClass{
    	void operator()(int a, int b)
    	{
    		cout << "ID:" << std::this_thread::get_id() << endl;
    		cout << a + b << endl;
    	}
    };
    int main()
    {
    	funcClass fc;//          ,        ,         
    	std::thread t(fc, 10, 20);
    	t.join();
    	system("pause");
    	return 0;
    }
    

    メンバー関数による構築
    #include 
    #include 
    using namespace std;
    struct A
    {
    	static void memberFunc(int a,int b)
    	{
    		cout << "hello from class member function :" << this_thread::get_id() << endl;
    		cout << a + b << endl;
    	}
    };
    int main(int argc, char **argv)
    {
    	thread t1(A::memberFunc,10,20);
    	t1.join();
    	system("pause");
    	return 0;
    }
    

    スレッド終了
    スレッドを作成します.デフォルトのステータスはjoinableステータスで、メインスレッドの待機が必要です.終了したスレッドを待機したくない場合は、スレッドが終了する前にスレッドオブジェクトのメンバー関数detachを使用してスレッドを分離する必要があります.
    加入式:join()
    join():スレッドの終了をアクティブに待機します.呼び出しプロセスでjoin()は、新しいスレッドが終了すると、join()が関連するリソースをクリーンアップし、戻ってきて、呼び出しスレッドが下に進みます.join()はスレッドに関するリソースをクリーンアップしているため、threadオブジェクトは破棄されたスレッドとは関係ありません.そのため、1つのスレッドのオブジェクトは毎回1回しかjoin()を使用できません.呼び出されたjoin()のjoinable()はfalseに戻ります.
    #include
    #include
    using std::cout;
    using std::endl;
    void threadRoute()
    {
    	cout << "ID:" << std::this_thread::get_id() << endl;
    }
    int main()
    {
    	cout << "Main ID:" << std::this_thread::get_id() << endl;
    	std::thread t(threadRoute);//thread              
    	cout << t.joinable() << endl;//   joinable  
    	t.join();//    ,        
    	cout << t.joinable() << endl;//join            ,     false 
    	system("pause");
    }
    

    分離式:detach()
    detach:呼び出しスレッドから新しいスレッドが分離され、その後は新しいスレッドと対話できません.あなたと彼女が別れたように、その後は連絡(インタラクション)がなくなり、彼女の後に消費された様々な資源もあなたが埋め合わせる必要はありません(資源を整理します).このときjoinable()を呼び出すと必ずfalseが返されます.分離したスレッドスレッドはバックグラウンドプロセス(孤児プロセス)となり,Linuxではinitが引き継ぎ,c++ではライブラリが引き継ぐ.
    #include
    #include
    using std::cout;
    using std::endl;
    void threadRoute()
    {
    	cout << "ID:" << std::this_thread::get_id() << endl;
    }
    int main()
    {
    	cout << "Main ID:" << std::this_thread::get_id() << endl;
    	std::thread t(threadRoute);//thread              
    	cout << t.joinable() << endl;//   joinable  
    	t.detach();
    	cout << t.joinable() << endl;//detach        ,      join
    	system("pause");
    }
    

    注意:threadオブジェクトが破棄される前に選択する必要があります.これは、スレッドがスレッドに追加または分離される前に終了し、その後分離すると、threadオブジェクトが破棄された後もスレッドが実行される可能性があるためです.
    スレッドの安全なthread
    threadオブジェクトは所有権を移行できます
    thread object is movable,not copyable,like std::unique_ptr or std::ifstream. std::moveは何も移動できません.唯一の機能は、左の値を強制的に右の値参照に変換することです.次に、右の値参照でこの値を使用して、意味を移動することができます.実装上、std::moveは基本的に1つのタイプ変換に等しい:static_cast(lvalue); 特筆すべきは、転化された左値であり、その生命期は左右値の転化に伴って変化していない.std::move変換の左値変数lvalueが直ちに解析されることが望ましい場合、失望するに違いない.
    #include
    #include
    
    using namespace std;
    void some_function();
    
    int main()
    {
    	thread t1(some_function); 
    	thread t2 = move(t1); //  std::move     t1       t2,
    	//  t2    some_function(), t1            
    	t1 = thread(some_function); //t1     
    }
    

    インテリジェントポインタ管理threadオブジェクト
    プライマリ・スレッドが新しいスレッドを作成した後、プライマリ・スレッドは他のスレッドの終了を待つだけでなく、他のことをする必要があることを知っています.プライマリ・スレッドは他のことをします.join関数の前に、プライマリ・スレッドが他の関数を呼び出したために異常になる可能性があります.これにより、プライマリ・スレッドはjoin関数を逃して直接異常処理に行く可能性があります.したがって,joinable状態のスレッドが孤児プロセスにならないことを保証するために,threadオブジェクトをスマートポインタに渡し,スマートポインタ構造関数でjoinを行うことができる.
    #include
    #include
    
    using std::cout;
    using std::endl;
    
    void threadRoute()//    
    {
    	cout << "ID:" << std::this_thread::get_id() << endl;
    }
    class Unique_ptr{
    public:
    	Unique_ptr(std::thread& t)//        ,     new          
    		:pt(t){}
    	~Unique_ptr()
    	{
    		if (pt.joinable())
    			pt.join();
    	}
    	Unique_ptr(const Unique_ptr&) = delete;
    	Unique_ptr operator=(const Unique_ptr&) = delete;
    private:
    	std::thread& pt;
    };
    
    void func()
    {
    	cout << "Main ID:" << std::this_thread::get_id() << endl;
    	std::thread t(threadRoute);
    	Unique_ptr pth(t);
    }//pth          ,    join  
    int main()
    {
    	func();
    	system("pause");
    }