0

私はマルチスレッドが初めてです。UNIXでc++を使用しています。

以下のコードでは、runSearch() に時間がかかるため、「cancel == true」とすぐに検索を強制終了できるようにしたいと考えています。関数 cancelSearch が別のスレッドによって呼び出されます。

この問題を解決する最善の方法は何ですか?

ありがとうございます..

--------------これは既存のコードです-------------------------

    struct SearchTask : public Runnable
    {
        bool cancel = false;

        void cancelSearch()
        {
           cancel = true;
        }

        void run()
        {
            cancel = false;
            runSearch();
            if (cancel == true)
            {
                return;
            }
            //...more steps.
        }
    }

編集:より明確にするために、runSearch() の実行に 10 分かかるとします。1 分後、cancel==true の場合、runSearch() が完了するまでさらに 9 分待つのではなく、すぐに run() を終了します。

4

5 に答える 5

2

検索操作の間ずっとフラグをチェックし続ける必要があります。このようなもの:

    void run()
    {
        cancel = false;            
        while (!cancel)
        {
            runSearch();
            //do your thread stuff...
        }
    }
于 2012-07-31T18:40:24.247 に答える
1

runSearch()を変更できないとおっしゃいました。pthreadにはpthread_setcancelstate()関数がありますが、特にRAIIセマンティクスを期待するC ++コードでは、これが安全だとは思いません。

安全なスレッドキャンセルは協調的でなければなりません。キャンセルされるコードは、キャンセルを認識し、それ自体の後でクリーンアップできる必要があります。コードがこれを行うように設計されておらず、単に終了した場合、プログラムはおそらく未定義の動作を示します。

このため、C++のstd:: threadはスレッドキャンセルのメソッドを提供せず、代わりに、他の回答が示しているように、コードを明示的なキャンセルチェックで記述する必要があります。

于 2012-07-31T19:07:37.860 に答える
0

アクション/デリゲートを受け入れるジェネリック メソッドを作成します。各ステップは、非常に小さく具体的なものにします。汎用メソッドに、「ステップ」と見なされるデリゲート/アクションを送信します。ジェネリック メソッドでは、cancel が true かどうかを検出し、true の場合に返します。キャンセルされた場合のステップは小さいため、スレッドが死ぬのにそれほど時間はかからないはずです。

これは、ステップが何をするかのコードなしで私ができる最善のアドバイスです。

また、注意してください:

 void run()
{
    cancel = false;
    runSearch();
    while (!cancel)
    {
        //do your thread stuff...
    }
}

あなたがしていることが反復でない場合、!cancel をチェックする前にスレッド全体を実行するため、機能しません。私が言ったように、ステップが何をするかについてさらに詳細を追加できれば、アドバイスを与えるのが簡単になります. 停止または強制終了したいスレッドを操作する場合、最善の策は、コードを非常に小さなステップに分割することです。

于 2012-07-31T18:45:51.327 に答える
0

応答を読むのは正しいです。スレッドでブロッキング関数を呼び出したからといって、それが魔法のように非ブロッキング呼び出しに変わるわけではありません。スレッドはプログラムの残りの部分に割り込むことはできませんが、runSearch 呼び出しが完了するまで待機する必要があります。

OK、これを回避する方法はありますが、必ずしも安全に使用できるとは限りません。

スレッドを明示的に強制終了できます。Windows では、スレッドの実行を強制終了するTerminateThread () を使用できます。いいですね。ただし、使用するのが非常に危険であることを除けば、すべてのリソースと呼び出しが強制終了されたスレッドで行われていることを正確に把握していない限り、次回は正しく動作しないアプリに遭遇する可能性があります。たとえば、runSearch が DB 接続を開いた場合、TerminateThread 呼び出しはそれを閉じません。同じことが、メモリ、ロードされた dll、およびそれらが使用するすべてに適用されます。プログラムを閉じて再起動できるように、完全に応答しないスレッドを強制終了するように設計されています。

上記のことと、それを使用しないという非常に強い推奨事項を考えると、次のステップは runSearch を外部の方法で呼び出すことです。別のプロセスでブロッキング呼び出しを実行すると、プロセスはより確実に強制終了されます。他のすべてを台無しにすることはありません。プロセスは終了し、メモリ、ヒープ、ロードされた dll などすべてをクリアします。したがって、スレッド内で CreateProcess を呼び出し、ハンドルを待ちます。結果をメインアプリに戻すには、IPC で何らかのフォームが必要になります (プロセスを強制終了するときに共有メモリをリセットするのが面倒になる可能性があるため、おそらく共有メモリを使用しないことをお勧めします)。このプロセスを強制終了する必要がある場合は、そのハンドルでExitProcessを呼び出します (または終了します)。Linux の場合) これらの終了呼び出しはプロセス内で呼び出す必要があるため、ブロッキング呼び出しのためにプロセス内でスレッドを実行する必要があることに注意してください。プロセスを外部で終了することはできますが、やはり危険です。スレッドを強制終了するほど危険ではありませんが、それでも時々つまずく可能性があります。(これにはTerminateProcessまたはkillを使用します)

于 2012-07-31T19:27:13.280 に答える
0

cancel基本的に、どこでもフラグをポーリングする必要があります。他にも使用できるトリックはありますが、それらはスレッド キャンセルのようにプラットフォーム固有のものであったり、割り込みのように一般的ではありません。

またcancel、アトミック変数である必要があります (std::atomic のように、またはミューテックスで保護されているだけです)。そうしないと、コンパイラは値をレジスタにキャッシュするだけで、別のスレッドからの更新が表示されない可能性があります。

于 2012-07-31T19:04:18.157 に答える