web-dev-qa-db-ja.com

C ++ 11でフューチャーをキャンセル/デタッチする方法はありますか?

私は次のコードを持っています:

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

using namespace std;

int sleep_10s()
{
    this_thread::sleep_for(chrono::seconds(10));
    cout << "Sleeping Done\n";
    return 3;
}

int main()
{
    auto result=async(launch::async, sleep_10s);
    auto status=result.wait_for(chrono::seconds(1));
    if (status==future_status::ready)
        cout << "Success" << result.get() << "\n";
    else
        cout << "Timeout\n";
}

これは1秒間待機し、「タイムアウト」を出力して終了することになっています。終了する代わりに、さらに9秒間待機し、「Sleeping Done」を出力してから、segfaultを実行します。フューチャーをキャンセルまたはデタッチする方法はありますか?フューチャーの実行が完了するのを待つのではなく、コードがメインの最後で終了しますか?

32
m42a

C++ 11標準は、std::asyncで開始されたタスクをキャンセルする直接的な方法を提供していません。定期的にチェックされる非同期タスクにアトミックフラグ変数を渡すなど、独自のキャンセルメカニズムを実装する必要があります。

ただし、コードがクラッシュすることはありません。 mainの終わりに達すると、resultに保持されているstd::future<int>オブジェクトが破棄され、タスクが完了するのを待って結果を破棄し、使用されているリソースをすべてクリーンアップします。

25

ここでは、アトミックブールを使用して1つまたは複数のフューチャーを同時にキャンセルする簡単な例を示します。 Atomic boolは、Cancellationクラス内にラップされる場合があります(好みによって異なります)。

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

using namespace std;

int long_running_task(int target, const std::atomic_bool& cancelled)
{
    // simulate a long running task for target*100ms, 
    // the task should check for cancelled often enough!
    while(target-- && !cancelled)
        this_thread::sleep_for(chrono::milliseconds(100));
    // return results to the future or raise an error 
    // in case of cancellation
    return cancelled ? 1 : 0;
}

int main()
{
    std::atomic_bool cancellation_token;
    auto task_10_seconds= async(launch::async, 
                                long_running_task, 
                                100, 
                                std::ref(cancellation_token));
    auto task_500_milliseconds = async(launch::async, 
                                       long_running_task, 
                                       5, 
                                       std::ref(cancellation_token));
// do something else (should allow short task 
// to finish while the long task will be cancelled)
    this_thread::sleep_for(chrono::seconds(1));
// cancel
    cancellation_token = true;
// wait for cancellation/results
    cout << task_10_seconds.get() << " " 
         << task_500_milliseconds.get() << endl;
}
15
baol