いつstd :: thread :: detachを使用すればよいですか?


139

std::threadアプリケーションを高速化するために使用する必要がある場合があります。join()スレッドが完了するまで待機することも知っています。これは理解しやすいですが、detach()呼び出すことと呼び出さないことの違いは何ですか?

なしdetach()では、スレッドのメソッドはスレッドを独立して使用して動作すると思いました。

切り離さない:

void Someclass::Somefunction() {
    //...

    std::thread t([ ] {
        printf("thread called without detach");
    });

    //some code here
}

デタッチして呼び出す:

void Someclass::Somefunction() {
    //...

    std::thread t([ ] {
        printf("thread called with detach");
    });

    t.detach();

    //some code here
}


stdboostスレッドはどちらも、POSIXスレッドdetachjoinモデルにしています。
n。「代名詞」m。

回答:


149

のデストラクタでstd::thread、次のstd::terminate場合に呼び出されます。

  • スレッドは結合されませんでした(t.join()
  • また、(でt.detach())切り離されませんでした

したがって、実行フローがデストラクタに到達する前に、常にjoinまたはdetachスレッドのいずれかを実行する必要があります。


プログラムが終了すると(つまり、main戻ります)、バックグラウンドで実行されている残りの切り離されたスレッドは待機しません。代わりに、それらの実行が一時停止され、スレッドローカルオブジェクトが破棄されます。

重要なことに、これはそれらのスレッドのスタックがほどかれていないため、一部のデストラクタが実行されないことを意味します。これらのデストラクタが行うことになっているアクションによっては、プログラムがクラッシュしたり、殺されたりした場合と同じくらい悪い状況になる可能性があります。うまくいけば、OSがファイルのロックなどを解放することを望みますが、共有メモリ、半分書き込まれたファイルなどが破損している可能性があります。


それで、あなたは使うべきですjoindetach

  • 使用する join
  • より高い柔軟性が必要で、自分でスレッドの完了を待機する同期メカニズムを提供する用意がある場合を除いて、この場合は、detach

私がpthread_exit(NULL);を呼び出す場合 main()では、exit()はmain()から呼び出されないため、分離されたすべてのスレッドが完了するまでプログラムは実行を続けます。次に、exit()が呼び出されます。
サウザートン2015年

1
@Matthieu、なぜstd :: threadのデストラクタに参加できないのですか?
ジョン・スミス

2
@johnsmith:すばらしい質問です!参加するとどうなりますか?スレッドが完了するまで待機します。例外がスローされると、デストラクタが実行されます...スレッドが終了するまで、例外の伝播は突然中断されます。特に現在中断されているスレッドからの入力を待機している場合など、そうしない理由はたくさんあります。したがって、設計者は、物議を醸すデフォルトを選択するのではなく、それを明示的な選択にすることを選択しました。
Matthieu M.16年

@Matthieu std :: threadのデストラクタに到達する前にjoin()を呼び出すことを意味すると思います。囲んでいるクラスのデストラクタをjoin()できますか?
Jose Quinteiro 2016年

4
@JoseQuinteiro:実際には、他のリソースとは異なり、デストラクタから参加しないことをお勧めします。問題は、参加してスレッドが終了、スレッドが終了するのを待つだけであり、スレッドを終了させるシグナルが設定されているのとは異なり、長時間待機している可能性があります... スタックの現在のスレッドをブロックしていますが巻き戻され、この現在のスレッドが終了するのを防ぎ、スレッドを待機しているスレッドをブロックします...したがって、適切な時間内に特定のスレッドを停止できることが確実でない限り、待機しないことが最善です。デストラクタで。
Matthieu M.

25

detachスレッドが完了するのを待つつもりがない場合は呼び出す必要がありますjoinが、代わりにスレッドは完了するまで実行を続け、メインスレッドが特別に待機することなく終了します。

detach基本的に、実装できるようにするために必要なリソースを解放しますjoin

スレッドオブジェクトがその寿命を終え、どちらjoindetach呼び出されていない場合は、致命的なエラーです。この場合terminateは呼び出されます。


12
スレッドが結合分離もされていない場合、ターミネートはデストラクタで呼び出されることに注意してください。
nosid 2014

11

スレッドを切り離すjoin()と、終了する前にスレッドを切り離す必要がなくなりますmain()

スレッドライブラリは実際には、そのような各スレッドの下でmainを待機しますが、気にする必要はありません。

detach()バックグラウンドで実行する必要があるタスクがあるが、その実行には関心がない場合に主に役立ちます。これは通常、一部のライブラリの場合です。バックグラウンドワーカースレッドを静かに作成してデタッチするため、気付くことさえありません。


これは質問の答えにはなりません。答えは基本的に「あなたが分離するときにあなたは分離する」と述べています。
rubenvb

7

この回答は、との違いを説明するのではなく、タイトルの質問に回答することを目的joinとしていdetachます。では、いつstd::thread::detach使用すべきですか?

適切にメンテナンスされたC ++コードでstd::thread::detachは、まったく使用しないでください。プログラマは、作成されたすべてのスレッドが正常に終了して、取得したすべてのリソースを解放し、その他の必要なクリーンアップアクションを実行することを確認する必要があります。これdetachは、呼び出しによってスレッドの所有権を放棄することはオプションではないためjoin、すべてのシナリオで使用する必要があることを意味します。

ただし、一部のアプリケーションは、無期限にブロックする機能を含む可能性のある、古くてよく設計およびサポートされていないAPIに依存しています。これらの関数の呼び出しを専用スレッドに移動して、他のものをブロックしないようにすることは一般的な方法です。そのようなスレッドを正常に終了させる方法はないので、を使用しても、joinプライマリスレッドがブロックされるだけです。これはdetach、たとえば、thread動的なストレージ期間でオブジェクトを割り当ててから意図的にリークするよりも、使用する方がそれほど邪魔にならない状況です。

#include <LegacyApi.hpp>
#include <thread>

auto LegacyApiThreadEntry(void)
{
    auto result{NastyBlockingFunction()};
    // do something...
}

int main()
{
    ::std::thread legacy_api_thread{&LegacyApiThreadEntry};
    // do something...
    legacy_api_thread.detach();
    return 0;
}

1

cppreference.comによると:

実行のスレッドをスレッドオブジェクトから分離し、独立して実行を継続できるようにします。割り当てられたリソースは、スレッドが終了すると解放されます。

detachを呼び出した後は*this、もはやスレッドを所有していません。

例えば:

  std::thread my_thread([&](){XXXX});
  my_thread.detach();

お知らせローカル変数は:my_threadの寿命は一方で、my_thread終わった、のデストラクタがstd::thread呼び出されると、std::terminate()デストラクタ内で呼び出されます。

ただし、を使用する場合はdetach()my_threadもう使用しないでください。のライフタイムmy_threadが終了しても、新しいスレッドには何も起こりません。


承知しました。今言ったことを元に戻します。@ TobySpeight
DinoStray 2018

1
&ラムダキャプチャで使用する場合は、参照によって外側のスコープの変数を使用していることに注意してください。参照するすべてのライフタイムがスレッドのライフタイムよりも長いことを確認してください。
DavidJ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.