std :: threadがまだ実行されているかどうかを確認する方法は?


84

std::threadがまだ実行されているかどうかを(プラットフォームに依存しない方法で)確認するにはどうすればよいですか?それはtimed_join()方法を欠いており、そのためのものでjoinable()はありません。

std::lock_guardスレッド内のaでミューテックスをロックし、ミューテックスのtry_lock()メソッドを使用して、それがまだロックされている(スレッドが実行されている)かどうかを判断することを考えましたが、不必要に複雑に思えます。

もっとエレガントな方法を知っていますか?

更新:明確にするために:スレッドが正常に終了したかどうかを確認したいと思います。「ぶら下がっている」スレッドは、この目的で実行されていると見なされます。


スレッドがまだ実行されているかどうかを確認することは、スレッドが実行されることを期待しwait()ている場合にのみ重要であり、実行されている場合は、スレッドがまだ実行されていない場合はwait()、定義上実行されている必要があります。しかし、この推論は不正確かもしれません。
ereOn 2012

実際、例外的な条件で終了するスレッドがあり、メインスレッドからまだ実行されているかどうかを確認したいのですが、それを待ちたくない(参加した)
kispaljr 2012

1
走ることとはどういう意味ですか?待機状態ではなくアクティブに処理しているということですか、それともスレッドがまだ存在していて終了していないということですか?
CashCow 2012

いつでもブーストを使用できます:)
CashCow 2012

4
あなたがそれに満足していなければ、あなたは答えを受け入れるべきではありませんでした。
ニコルボーラス2012

回答:


117

C ++ 11std::asyncstd::future使用してタスクを実行する場合は、のwait_for関数std::futureを使用して、スレッドが次のように適切に実行されているかどうかを確認できます。

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    /* Run some task on new thread. The launch policy std::launch::async
       makes sure that the task is run asynchronously on a new thread. */
    auto future = std::async(std::launch::async, [] {
        std::this_thread::sleep_for(3s);
        return 8;
    });

    // Use wait_for() with zero milliseconds to check thread status.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    auto result = future.get(); // Get result.
}

を使用する必要がある場合はstd::thread、を使用std::promiseして将来のオブジェクトを取得できます。

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    // Create a promise and get its future.
    std::promise<bool> p;
    auto future = p.get_future();

    // Run some task on a new thread.
    std::thread t([&p] {
        std::this_thread::sleep_for(3s);
        p.set_value(true); // Is done atomically.
    });

    // Get thread status using wait_for as before.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    t.join(); // Join thread.
}

これらの例は両方とも次のように出力されます。

Thread still running

これはもちろん、タスクが終了する前にスレッドのステータスがチェックされるためです。

しかし、繰り返しになりますが、他の人がすでに述べたように、それを行う方が簡単かもしれません。

#include <thread>
#include <atomic>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    std::atomic<bool> done(false); // Use an atomic flag.

    /* Run some task on a new thread.
       Make sure to set the done flag to true when finished. */
    std::thread t([&done] {
        std::this_thread::sleep_for(3s);
        done = true;
    });

    // Print status.
    if (done) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    t.join(); // Join thread.
}

編集:

std::packaged_taskを使用するstd::threadよりもクリーンなソリューションのために使用するためのものもありますstd::promise

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    // Create a packaged_task using some task and get its future.
    std::packaged_task<void()> task([] {
        std::this_thread::sleep_for(3s);
    });
    auto future = task.get_future();

    // Run task on new thread.
    std::thread t(std::move(task));

    // Get thread status using wait_for as before.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        // ...
    }

    t.join(); // Join thread.
}

2
いい答えだ。戻り値とfutureのないスレッドでも機能することを付け加えて
おき

このコードの理由は何std::atomic<bool> done(false);ですか?boolデフォルトではアトミックではありませんか?
ハイエンジェル

6
@YagamyLight C ++では、std::atomic。でラップされていない限り、デフォルトではアトミックなものはありません。sizeof(bool)は実装で定義されており、1より大きい場合があるため、部分的な書き込みが発生する可能性があります。キャッシュ・コヒーレンスの問題もあります...
SNPは


1
std :: chrono_literalsをコンパイルするにはC ++ 14が必要になることに注意してください
Patrizio Bertoni

6

簡単な解決策は、スレッドが定期的にtrueに設定し、ステータスを知りたいスレッドによってチェックされてfalseに設定されるブール変数を設定することです。変数が長い間falseの場合、スレッドはアクティブであるとは見なされなくなります。

よりスレッドセーフな方法は、子スレッドによって増加するカウンターを用意することです。メインスレッドはカウンターを保存された値と比較し、時間がかかりすぎると子スレッドはアクティブでないと見なされます。

ただし、C ++ 11には、ハングしたスレッドを実際に強制終了または削除する方法がないことに注意してください。

編集スレッドが正常に終了したかどうかを確認する方法:基本的に、最初の段落で説明したのと同じ手法。ブール変数をfalseに初期化します。子スレッドが最後に行うことは、それをtrueに設定することです。次に、メインスレッドはその変数をチェックし、trueの場合、多くの(存在する場合)ブロッキングなしで子スレッドで結合を実行します。

Edit2例外のためにスレッドが終了する場合は、2つのスレッド「メイン」関数があります。最初のスレッドにはtry-catchがあり、その中に2番目の「実際の」メインスレッド関数が呼び出されます。この最初のメイン関数は、「have_exited」変数を設定します。このようなもの:

bool thread_done = false;

void *thread_function(void *arg)
{
    void *res = nullptr;

    try
    {
        res = real_thread_function(arg);
    }
    catch (...)
    {
    }

    thread_done = true;

    return res;
}

1
それがOPの「実行中」の定義である場合。
CashCow 2012

多分あなたは私を誤解しました。スレッドがきれいに終了したかどうかを確認したい。言葉遣いが不明瞭でごめんなさい。
kispaljr 2012

7
異なるスレッドが読み取りと書き込みを行っているthread_done場合、このコードはメモリバリアなしで壊れます。std::atomic<bool>代わりに使用してください。
ildjarn 2012

1
私は複数のワーカースレッドについて言及していませんでしboolた。メインスレッドがそこから読み取る間に、単一のワーカースレッドが書き込みを行うことについて言及していました。これはメモリバリアが必要です。
ildjarn 2012

3
ここでaが必要な理由については、この質問を確認してくださいstd::atomic<bool>
ロバートリューガー2013年

3

結合メソッドでブロックせずにスレッドの終了を検出するために使用できるこの単純なメカニズム。

std::thread thread([&thread]() {
    sleep(3);
    thread.detach();
});

while(thread.joinable())
    sleep(1);

2
スレッドを切り離すことは、最終的には望むものではありません。そうしない場合はjoin()、スレッドがそのjoinable()プロパティを失うのを待たないスレッドから呼び出す必要があります。そうしないと、無限にループします(つまりjoinable()、スレッドが実際になるまでtrueを返します)join()edであり、終了するまで)
Niklas R

結合可能とは、スレッドがスレッドハンドルを保持していることを意味します。スレッドが完了した場合でも、参加可能です。スレッドの終わりを待たずにチェックする必要がある場合は、ここに解決策があります。ほんの数行のコードです。なぜ最初に試しなかったのですか?
Evgeny Karpov 2016

私はそうしました、そして私が言いたいのは、あなたがそのthread.detach()部分を取り除いても、上記のプログラムは決して終わらないということです。
Niklas R

はい、そうではありません。それが最終的にデタッチと呼ばれる理由です。
Evgeny Karpov 2016

1
デタッチを呼び出すこの方法では、ミューテックスやその他のより複雑なソリューションが不要になります。私はそれを使用し、それは動作します!答えてくれてありがとう。
2016

1

実行中のスレッドと呼び出し元のスレッドの両方がアクセスできるミューテックスを作成します。実行中のスレッドは、開始時にミューテックスをロックし、終了するとミューテックスのロックを解除します。スレッドがまだ実行されているかどうかを確認するために、呼び出し元のスレッドはmutex.try_lock()を呼び出します。その戻り値はスレッドのステータスです。(try_lockが機能した場合は、必ずミューテックスのロックを解除してください)

これに関する小さな問題の1つである、mutex.try_lock()は、スレッドが作成されてからミューテックスをロックするまでの間にfalseを返しますが、これは少し複雑な方法を使用して回避できます。


-1std::mutexこの種のシグナリングには使用しないでください(主にミューテックスが通常どのように実装されているかという理由による)。atomic_flag少ないオーバーヘッドの方法で、この場合には同じようにうまく動作します。Astd::futureは、意図をより明確に表現するため、さらに優れている可能性があります。また、try_lockこれは誤って失敗する可能性があるため、返されるの必ずしもスレッドのステータスではないことを覚えておいてください(ただし、この特定のケースではおそらくそれほど害はありません)。
ComicSansMS 2013年

1

スレッドのIDがデフォルトで構築されたstd :: thread :: id()と異なるかどうかはいつでも確認できます。実行中のスレッドには、常に本物の関連付けられたIDがあります。派手すぎるものは避けてください:)


0

確かに、ミューテックスでラップされた変数をに初期化しfalseて、スレッドがtrue終了する前に最後に行うように設定します。それはあなたのニーズに十分な原子ですか?


1
とにかくミューテックスを使用する場合、私の解決策(ブール値なしでミューテックスのみを使用)がよりエレガントであると感じます。スレッドセーフなブール値を絶対に使用したい場合は、代わりにstd :: atomic <bool>をお勧めします。ほとんどの実装では、ロックフリーになります。
kispaljr 2012

なぜロックするのですか?1つのスレッドは読み取りのみ、1つのスレッドは書き込みのみです。そして、ワードサイズの書き込みは、いずれの場合もIIRCでアトミックです。
xeo 2012

1
@Xeo:書き込みはアトミックである可能性がありますが、別のスレッド(別のCPUで実行されている可能性があります)で書き込まれた値を確認する場合は、メモリバリアが必要です。std::atomic<bool>あなたのためにこれを世話します、それがそれが本当の答えIMOである理由です。
ildjarn 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.