10

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

とを使用して非同期で実行されるメンバー関数がありstd::futureますstd::async。場合によってはキャンセルする必要があります。(関数はオブジェクトの近くを連続してロードし、ロード中にオブジェクトが範囲外になることがあります。)同じ問題に対処するこの質問の回答をすでに読んでいますが、機能させることができません。

これは、私の実際のプログラムと同じ構造の単純化されたコードです。非同期の実行中に呼び出しStart()を行うとKill()、のアクセス違反が原因でクラッシュが発生しますinput

私の目には、コードは次のように機能するはずです。がKill()呼び出されると、実行フラグは無効になります。次のコマンドget()は、スレッドが終了するのを待つ必要があります。これは、実行中のフラグをチェックするため、すぐに終了します。スレッドがキャンセルされた後、inputポインタは削除されます。

#include <vector>
#include <future>
using namespace std;

class Class
{
    future<void> task;
    bool running;
    int *input;
    vector<int> output;

    void Function()
    {
        for(int i = 0; i < *input; ++i)
        {
            if(!running) return;
            output.push_back(i);
        }
    }

    void Start()
    {
        input = new int(42534);
        running = true;
        task = async(launch::async, &Class::Function, this);
    }

    void Kill()
    {
        running = false;
        task.get();
        delete input;
    }
};

スレッドは実行中のフラグをfalseに切り替えることに気付いていないようです。私の間違いは何ですか?

4

1 に答える 1

10

誰も実際に質問に答えていないので、私は答えます。

変数への書き込みと読み取りrunningはアトミック操作ではないため、コードには2つのスレッド間の同期を引き起こすものはなく、非同期スレッドが変数が変更されたことを確認することはできません。

発生する可能性のある1つの方法は、コンパイラがのコードを分析しFunction、そのスレッドに変数への書き込みがないことを確認し、他のスレッドによる書き込みがアトミックオブジェクトではないため、完全に表示される必要がないことです。これにコードを再配置することは合法です:

void Function()
{
    if(!running) return;
    for(int i = 0; i < *input; ++i)
    {
        output.push_back(i);
    }
}

明らかに、このコードでrunningは、関数の開始後に変更を加えても、ループは停止しません。

C ++標準で2つのスレッドを同期するには、ミューテックスを使用しrunningてミューテックスがロックされているときにのみ変数の読み取りまたは書き込みを行う方法と、変数をアトミック変数にする方法の2つがあります。あなたの場合、runningからboolに変更atomic<bool>すると、変数への書き込みが変数からの読み取りと同期され、非同期スレッドが終了します。

于 2013-01-13T17:13:26.217 に答える