web-dev-qa-db-ja.com

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

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

スレッド内で_std::lock_guard_でミューテックスをロックし、ミューテックスのtry_lock()メソッドを使用して、まだロックされている(スレッドが実行されている)かどうかを判断することを考えましたが、私。

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

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

70
kispaljr

C++ 11 std::asyncおよびstd::futureを使用してタスクを実行する場合、wait_forstd::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.
}
95
Snps

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

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

ただし、C++ 11には、ハングしたスレッドを実際に強制終了または削除する方法はありません。

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

Edit2スレッドが例外のために終了する場合、2つのスレッド「メイン」関数があります。最初の関数には、2番目の関数を呼び出すtry-_catchがあります「実際の」メインスレッド関数。この最初のメイン関数は、「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;
}

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

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

while(thread.joinable())
    sleep(1);
3
Evgeny Karpov

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

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

1
Nathan Fox

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

0
Michal Turlik

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