1

我正在使用带有 Visual C++ 2010 的并发运行时,并且对parallel_invoketask_group(PPL 或并行模式库的一部分)的功能感兴趣。我希望能够通过函数对象(而不是 lambda 函数或函数指针)启动两个并行操作,但由于错误,我无法编译代码:

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

但是,如果我将 C::operator()() 设为 const,那么我将失去函数对象的许多好处,即它的状态是可变的,并且在调用之间在内部保持不变。我在这里错过了什么吗?有没有办法可以并行调用非常量函数对象?

顺便说一句,我意识到我可以使用Asynchronous Agents Library,并从 Concurrency::agent 类派生类,但请考虑超出此问题的范围(部分原因是缺少异常处理和取消选项)。

我只是对我可以用 PPL 做什么感兴趣,虽然有 lambda 函数和函数指针的示例,但我找不到或创建任何具有函数对象的示例,这些函数对象不仅仅是并行的“Hello World”。我正在寻找真正利用函数对象的东西,如果可能的话,还有并发容器。

4

2 回答 2

2

函子必须是不可变的,因为当它们通过 parallel_invoke 和 task_group::run 调度时,它们会被复制,并且在状态累积期间出现竞争条件的可能性很高。特别是 task_group::run 任务的生命周期有可能比任务声明的地方更长寿(即,您在堆栈上声明它并且堆栈退出但任务尚未运行)

可用于解决此问题的最简单技术是在 lambda 中通过引用捕获函子(是的,我知道您说过您不想直接使用 lambda)。

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

您还可以使用调度程序类的“轻量级任务”设施(参见 Scheduler::ScheduleTask),它不需要 const,因为它具有典型的 void* API。

您需要构建一个包装函数来处理这个问题,但这很简单,在http://code.msdn.com/concrtextras的示例包中有一个

-瑞克

于 2010-11-15T19:04:39.487 回答
0

为什么不直接将 operator()() 设为 const 并使用 mutable 来保持状态?

但是,当然,您在这里面临一些严重的风险,因为您将负责所有与更改该状态相关的线程安全问题。这些函数对象不应该这样做。

编辑:说真的。只需使用 lambda。函数对象在 VS2010 中已失效。为什么 C++0x 编译器要发布代码,显示他们花费时间和金钱替换的过去的函数习语?这是矛盾和疯狂的。

于 2010-11-15T20:05:15.513 回答