【C++同時およびマルチスレッド】2_スレッドの起動、終了、スレッドの作成に関するさまざまな方法、join,detach


プレゼンテーションスレッドの実行の開始と終了
  • は、main関数からメインスレッドが返されると、プロセス内の一意のメインスレッドが起動し、全体が終了するプロセスを実行することができる.
  • で作成されたサブスレッドは、関数の実行が完了すると、現在のサブスレッドが終了する初期関数から実行する必要があります.
  • プロセス終了フラグ:メインスレッドが終了したかどうか.プライマリ・スレッドの実行が完了すると、プロセス全体が終了します.通常、他のサブスレッドが完了していない場合、サブスレッドは強制的に終了します(例外:detach).

  • thread
    スレッド実行オブジェクトを作成します.
    join
    サブスレッドの実行が終了するまで、メインスレッド(呼び出しスレッド)をブロックします.
     :      joinable    true    (   false        std::system_error   )

    detach
    サブスレッドとプライマリスレッドの関連付けを分離すると、サブスレッドはシステムのバックグラウンドに存在して独立して実行を継続することができ、プライマリスレッドはプライマリスレッドの制御権を得ることができません.すなわち、プライマリスレッドが終了し、サブスレッドも終了しません.サブスレッドが終了すると、C++ランタイムライブラリがスレッド関連のリソースのクリーンアップを担当します.
     :      joinable    true    (   false        std::system_error   )

    joinable
    スレッドオブジェクトがjoin()またはdetach()を呼び出すことができるかどうかを判断し、trueを返すことができ、falseを返すことができません.
    Test1: thread, join, joinable
    #include 
    #include 
    
    using namespace std;
    
    void thread_func()
    {
        cout << "thread_func begin" << endl;
    
        for (uint32_t i=0; i<10000; ++i)
        { }
    
        cout << "thread_func end" << endl;
    }
    
    int main()
    {
        cout << "main begin" << endl;
    
        thread my_thread(thread_func);
    
        if (my_thread.joinable())   //  :    join     joinable   !!! 
        {
            cout << "my_thread.joinable() " << my_thread.joinable() << endl;
    
            my_thread.join();
        }
    
        cout << "my_thread.joinable() " << my_thread.joinable() << endl;
    
        cout << "main end" << endl;
    
        return 0;
    }

    出力:
    main begin
    my_thread.joinable() 1
    thread_func begin
    thread_func end
    my_thread.joinable() 0
    main end

    Test2: detach
    #include 
    #include 
    
    using namespace std;
    
    void thread_func()
    {
        cout << "thread_func begin" << endl;
    
        for (uint32_t i=0; i<10000; ++i)
        { }
    
        cout << "thread_func end" << endl;
    }
    
    int main()
    {
        cout << "main begin" << endl;
    
        thread my_thread(thread_func);
    
        if (my_thread.joinable())
        {
            my_thread.detach();
        }
    
        cout << "main end" << endl;
    
        return 0;
    }

    出力:【プロセスが終了し、サブスレッドがバックグラウンドで実行され、コンソールで出力できません】
    main begin
    main end

    スレッドの作成方法
    スレッドパラメータは呼び出し可能なオブジェクトです.呼び出し可能なオブジェクトには、関数、関数ポインタ、lambda式、std::bindで作成されたオブジェクト、std::functionで作成されたオブジェクト、および関数呼び出し演算子が再ロードされたクラスオブジェクトが含まれます.
    #include 
    #include 
    
    using namespace std;
    
    void thread_func()
    {
        cout << "thread_func begin" << endl;
    
        for (uint32_t i=0; i<10000; ++i)
        { }
    
        cout << "thread_func end" << endl;
    }
    
    auto thread_lambda = []{
        cout << "thread_lambda begin" << endl;
    
        for (uint32_t i=0; i<10000; ++i)
        { }
    
        cout << "thread_lambda end" << endl;
    };
    
    class thread_class {
    public:
        thread_class() {
            cout << "thread_class " << this << endl;
        }
    
        thread_class(const thread_class&) {
            cout << "thread_class(const thread_class&) " << this << endl;
        }
    
        ~thread_class() {
            cout << "~thread_class() " << this << endl;
        }
    
        void operator () () {
            cout << "thread_class begin" << endl;
    
            for (uint32_t i=0; i<10000; ++i)
            { }
    
            cout << "thread_class end" << endl;
        }
    };
    
    class base {
    public:
        void func()
        {
            cout << "base::func begin" << endl;
    
            for (uint32_t i=0; i<10000; ++i)
            { }
    
            cout << "base::func end" << endl;
        }
    };
    
    int main()
    {
        cout << "main begin" << endl;
    
        cout << "function:" << endl;
        thread my_thread1(thread_func);
        if (my_thread1.joinable())
            my_thread1.join();
    
        cout << "lambda:" << endl;
        thread my_thread2(thread_lambda);
        if (my_thread2.joinable())
            my_thread2.join();
    
        cout << "class:" << endl;
        thread_class tc;
        thread my_thread3(tc);  //   :                  !!
        if (my_thread3.joinable())
            my_thread3.join();
    
        cout << "class::function:" << endl;
        base b;
        thread my_thread4(&base::func, &b);
        if (my_thread4.joinable())
            my_thread4.join();
    
        cout << "main end" << endl;
    
        return 0;
    }

    出力:
    main begin
    function:
    thread_func begin
    thread_func end
    lambda:
    thread_lambda begin
    thread_lambda end
    class:
    thread_class 0x62fde7
    thread_class(const thread_class&) 0x62fd77
    thread_class(const thread_class&) 0x6917f8
    ~thread_class() 0x62fd77
    thread_class begin
    thread_class end
    ~thread_class() 0x6917f8
    class::function:
    base::func begin
    base::func end
    main end
    ~thread_class() 0x62fde7

    説明:
                                 ?
         QT5.15.2 STL     
    // 1. thread           
    template
          explicit
          thread(_Callable&& __f, _Args&&... __args)
          {
    #ifdef GTHR_ACTIVE_PROXY
        // Create a reference to pthread_create, not just the gthr weak symbol.
        auto __depend = reinterpret_cast(&pthread_create);
    #else
        auto __depend = nullptr;
    #endif
            _M_start_thread(_S_make_state(
              __make_invoker(std::forward<_callable>(__f),
                     std::forward<_args>(__args)...)),
            __depend);
          }
          
    // 2. __make_invoker    __make_invoker      
    template
          static _Invoker<__decayed_tuple _args...="">>
          __make_invoker(_Callable&& __callable, _Args&&... __args)
          {
        return { __decayed_tuple<_callable _args...="">{
            std::forward<_callable>(__callable), std::forward<_args>(__args)...
        } };
          }
    
    // 3. __decayed_tuple   tuple   ,    tuple   ,        
    template
          using __decayed_tuple = tuple::type...>;
          
    // 4. new _Impl{...},         
    template
      static _State_ptr
      _S_make_state(_Callable&& __f)
      {
    using _Impl = _State_impl<_callable>;
    return _State_ptr{new _Impl{std::forward<_callable>(__f)}};
      }

    注意:
    呼び出し可能なクラスオブジェクトで作成されたスレッドオブジェクトにクラスオブジェクトのコピーがあります!!これにより、コピー動作がトリガーされ、パフォーマンスが損なわれる可能性があります.