1

Visual C ++ 2010で同時実行ランタイムを使用していて、parallel_invokeおよびtask_group(PPLまたは並列パターンライブラリの一部)の機能に興味があります。(ラムダ関数や関数ポインターではなく)関数オブジェクトを介して2つの並列アクションを開始できるようにしたいのですが、エラーのためにコードをコンパイルできません:

error C3848: expression having type 'const C' would lose some const-volatile qualifiers in order to call 'void C::operator ()(void)'

しかし、C :: operator()()をconstにすると、関数オブジェクトの多くの利点が失われます。つまり、その状態は変更可能であり、呼び出し間で内部的に維持されます。ここで何かが足りませんか?非定数関数オブジェクトを並行して呼び出す方法はありますか?

ところで、非同期エージェントライブラリを使用して、Concurrency :: agentクラスからクラスを派生させることができることを認識していますが、この質問の範囲を超えていることを考慮してください(一部には例外処理とキャンセルオプションがないため)。

PPLで何ができるかに興味があり、ラムダ関数と関数ポインターを使用した例はありますが、並列の「HelloWorld」以上の機能を実行する関数オブジェクトを使用した例を見つけたり作成したりすることはできませんでした。関数オブジェクトと、可能であれば並行コンテナーも実際に活用するものを探しています。

4

2 に答える 2

2

ファンクターは、parallel_invokeおよびtask_group :: runを介してスケジュールされたときにコピーされ、状態の蓄積中の競合状態の可能性が高いため、不変である必要があります。特にtask_group::runを使用すると、タスクの存続期間は、タスクが宣言された場所よりも長くなる可能性があります(つまり、スタックで宣言し、スタックが終了しても、タスクはまだ実行されていません)。

これを回避するために使用できる最も簡単な手法は、ラムダで参照によってファンクターをキャプチャすることです(そうです、ラムダを直接使用したくないと言っていました)。

   NonConstFunctor func;
   Concurrency::task_group tasks;
   // c3848
   //tasks.run(func);
   //work around this by capturing func by reference
   tasks.run([&func](){func();});

また、通常のvoid * APIを備えているため、constを必要としないスケジューラークラスの「軽量タスク」機能(Scheduler :: ScheduleTaskを参照)を使用することもできます。

これを処理するにはラッパー関数を作成する必要がありますが、これは簡単で、http://code.msdn.com/concrtextrasのサンプルパックに含まれています。

-リック

于 2010-11-15T19:04:39.487 に答える
0

なぜoperator()()をconstにし、状態を維持するために可変を使用しないのですか?

ただし、もちろん、ここではいくつかの重大なリスクがあります。これは、その状態の変更に関するスレッドセーフ関連のすべての問題に責任があるためです。これらの関数オブジェクトはそれを行うことは想定されていません。

編集:真剣に。ラムダを使用するだけです。VS2010では関数オブジェクトは機能していません。C ++ 0xコンパイラが、置き換えに時間とお金を費やした過去の関数イディオムを示すコードを投稿する必要があるのはなぜですか?それは矛盾していて非常識です。

于 2010-11-15T20:05:15.513 に答える