C++ マルチスレッド学習 01 オブジェクトのライフサイクルとスレッドの終了と待機

サブスレッド:

void ThreadMain()
{
    
    
    cout << "begin sub thread main " << this_thread::get_id() << endl;
    for (int i = 0; i < 10; i++)
    {
    
    
        if (!is_exit) break;
        cout << "in thread " << i << endl;
        this_thread::sleep_for(chrono::seconds(1));//1000ms
    }
    cout << "end sub thread main " << this_thread::get_id() << endl;
}

main 関数の 3 つのケース:
01:

int main(int argc, char* argv[])
{
    
    
{
    
    
thread th(ThreadMain);
}
getchar();
 return 0;
}

ここに画像の説明を挿入

explicit thread(_Fn&& _Fx, _Args&&... _Ax) {
    
    
        using _Tuple                 = tuple<decay_t<_Fn>, decay_t<_Args>...>;
        auto _Decay_copied           = _STD make_unique<_Tuple>(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...);
        constexpr auto _Invoker_proc = _Get_invoke<_Tuple>(make_index_sequence<1 + sizeof...(_Args)>{
    
    });

#pragma warning(push)
#pragma warning(disable : 5039) // pointer or reference to potentially throwing function passed to
                                // extern C function under -EHc. Undefined behavior may occur
                                // if this function throws an exception. (/Wall)
        _Thr._Hnd =
            reinterpret_cast<void*>(_CSTD _beginthreadex(nullptr, 0, _Invoker_proc, _Decay_copied.get(), 0, &_Thr._Id));
#pragma warning(pop)

        if (_Thr._Hnd) {
    
     // ownership transferred to the thread
            (void) _Decay_copied.release();
        } else {
    
     // failed to start thread
            _Thr._Id = 0;
            _Throw_Cpp_error(_RESOURCE_UNAVAILABLE_TRY_AGAIN);
        }

これは、関数ポインタをスレッド コンストラクタのパラメータとして使用すると、ハンドル _Thr._Hnd が生成されるためです.このハンドルのライフサイクルはメイン スレッドと一致しています.メイン スレッドが終了すると、ハンドルもこのため、子スレッドがまだ実行中の場合はエラーになります

02

int main(int argc, char* argv[])
{
    
    
{
    
    
thread th(ThreadMain);
th.detach(); }
  getchar();
 return 0;
}

detach() を使用して子スレッドをメイン スレッドから分離することは、子スレッドをデーモン スレッドに変換し、ハンドルなどのリソースのライフ サイクルを子スレッドに渡すことと同じです。注: 子スレッドは必ずしも終了しません。サブスレッドは、メインスレッドで変数
java デーモンスレッドを:
デーモンスレッドは、プログラムの実行中にバックグラウンドで一般的なサービスを提供するスレッドを指します. このスレッドプログラムの不可欠な部分ではありません。
detach() の機能は、サブスレッドとメインスレッドの間の関連付けを分離することです。つまり、detach() の後、サブスレッドはバックグラウンドで独立して実行され続け、メインスレッドはもはやできませんサブスレッドの制御を取得します. 実行も終了しません. メイン スレッドが終了すると、ランタイム ライブラリは子スレッドに関連するリソースをクリーンアップします。

使用シナリオ: メイン スレッドをサブスレッドと一緒に実行したいが、サブスレッド オブジェクトを特別に維持したくない
ここに画像の説明を挿入

03

bool is_exit = false;
void ThreadMain()
{
    
    
    for (int i = 0; i < 10; i++)
    {
    
    
        if (is_exit) break;
        cout << "in thread " << i << endl;
        this_thread::sleep_for(chrono::seconds(1));//1000ms
    }
}
int main(int argc, char* argv[])
{
    
    
        thread th(ThreadMain);
        for (int i = 0; i < 10; i++)
        {
    
    
            if(i==5)
               th.join();
          
            this_thread::sleep_for(chrono::seconds(1));
            cout << "a   " << endl; 
        }
    return 0;
}

th.join() メソッドは、子スレッドをメイン スレッドに追加し、メイン スレッドの CPU 実行時間を子スレッドに与えるために使用されます。たとえば、スレッド A の Join() メソッドがスレッド B で呼び出された場合、スレッド B は、スレッド A の実行が終了するまで実行を継続しません。参加する前に、CPU は両方のスレッドにタイム スライスを割り当て (スレッドは CPU スケジューリングの基本単位です)、参加後、サブスレッドは最初に元のメイン スレッドのタイム スライスを使用します。std::thread t(func) の後の適切な場所で呼び出され、その機能は、リソースのリークを回避するために、対応する作成されたスレッドのリソースをリサイクルすることです。
ここに画像の説明を挿入

最初の 5 秒間で、メイン スレッドとサブ スレッドが交互に印刷することがわかります. 5 秒で、サブ スレッドがメイン スレッドをブロックし、メイン スレッドは、サブ スレッドの実行が終了した後にのみ実行できます.
メインスレッドが次のように記述されている場合:

 for (int i = 0; i < 10; i++)
        {
    
    
            if (i == 5)
                //th.join();
            is_exit = true; //通知子线程退出
            this_thread::sleep_for(chrono::seconds(1));
            cout << "a   " << endl; 
        }

その後、サブスレッドが実行を終了したように見えても、エラーが報告されます。サブスレッドはまだ準備完了キューにマウントされている可能性があり、他の操作は実際には CPU によって終了と見なされません。th.join() を使用して待機します。それ以外の場合はそのハンドル メインスレッドによって解放されると問題が発生します。
その理由は公式ドキュメントで見ることができます:
If joinable() then terminate(), そうでなければ効果なし. [ 注: デストラクタで joinable() スレッドを暗黙的にデタッチまたは結合すると、(デタッチの場合) 正確さをデバッグするのが難しくなる可能性があります。または、例外が発生した場合にのみ発生するパフォーマンス (結合の場合) バグ. したがって、プログラマは、スレッドがまだ結合可能である間、デストラクタが決して実行されないようにする必要があります
.

おすすめ

転載: blog.csdn.net/qq_42567607/article/details/125457433