C++ std::future::wait应该使用这么多CPU吗?有没有性能更好的电话?

C++ std::future::wait应该使用这么多CPU吗?有没有性能更好的电话?,c++,multithreading,c++11,C++,Multithreading,C++11,编辑:tl;dr——这个问题似乎仅限于一小部分操作系统/编译器/库的组合,现在在GCC Bugzilla中被跟踪,这要归功于。 我在等待未来,我注意到top显示了100%的CPU使用率,strace显示了源源不断的futex呼叫: ... [pid 15141] futex(0x9d19a24, FUTEX_WAIT, -2147483648, {4222429828, 3077922816}) = -1 EINVAL (Invalid argument) ... 这是在Linux 4.2.0

编辑:tl;dr——这个问题似乎仅限于一小部分操作系统/编译器/库的组合,现在在GCC Bugzilla中被跟踪,这要归功于。

我在等待未来,我注意到
top
显示了100%的CPU使用率,
strace
显示了源源不断的
futex
呼叫:

...
[pid 15141] futex(0x9d19a24, FUTEX_WAIT, -2147483648, {4222429828, 3077922816}) = -1 EINVAL (Invalid argument)
...
这是在Linux 4.2.0(32位
i686
)上使用gcc版本5.2.1编译的

以下是我的最低可行示例计划:

#include <future>
#include <iostream>
#include <thread>
#include <unistd.h>

int main() {
  std::promise<void> p;
  auto f = p.get_future();

  std::thread t([&p](){
    std::cout << "Biding my time in a thread.\n";
    sleep(10);
    p.set_value();
  });

  std::cout << "Waiting.\n";
  f.wait();
  std::cout << "Done.\n";

  t.join();
  return 0;
}
是否有更高性能的替代方案?

下面是一个逻辑上相似的程序,它使用了
std::condition\u变量
,性能似乎要好得多:

#包括
#包括
#包括
#包括
#包括
int main(){
bool-done=0;
std::互斥m;
std::条件变量cv;
标准:螺纹t([&m,&cv,&done](){
std::cout不,不应该。它通常效果很好

(在评论中,我们试图确定关于一个特定的中断配置的更多信息,在该配置中,生成的可执行文件似乎是自旋等待,但我相信这就是答案。在最新的g++中,确定这是否仍然是32位目标上的自旋等待仍然很好。)

是promise future通信通道的“推送”端:在共享状态中存储值的操作与(如
std::memory\u order
中所定义的)等待共享状态的任何函数(如
std::future::get
)的成功返回同步

我假设这包括
std::future::wait

以原子方式将值存储到共享状态并使状态就绪。 该操作的行为类似于
set\u value
set\u exception
set\u value\u at\u thread\u exit
,以及
set\u exception\u at\u thread\u exit
在更新承诺对象时获取与承诺对象关联的单个互斥锁

虽然他们用promise对象而不是共享状态来描述同步有点令人不安,但其意图非常清楚


cppreference.com继续以上述问题中不起作用的方式使用它。(“此示例显示如何将承诺用作线程之间的信号。”)

不,当然不应该这样做,这是实现中的错误,而不是
std::future
的属性

这就是现在-不断调用
futex(2)
的循环已经启动


它看起来像是
syscall
函数缺少的一个简单参数,因此向内核传递了一个垃圾指针,该指针抱怨它不是一个有效的
timespec*
参数。我正在测试修复程序,明天将提交,因此它将在GCC 5.4中得到修复。也许您应该找出用n无效参数,并修复它…我打赌在某个地方有类似
的代码,而(!future\u is\u done)futex(…)
他们希望调用
futex
等待一段时间,但如果失败,它会意外地变成一个无限循环。我想给互联网一个机会,在假设我的代码是别人的错误之前,告诉我它有多错误,但是的,感觉
libstdc++
要么有错误,要么有错误有点像未说明的假设。linux 4.2.0(ubuntu 15.10),g++5.2.1,64位,这里没有明显的cpu使用率。@RobStarling的确,
-m32
我可以重现您描述的问题:100%的cpu使用率和大量的futex等待。我不觉得这令人不安,因为在调用时共享状态与该承诺相关联,共享状态一次只能与一个承诺相关联时间,互斥体仅由承诺上的操作所需,而不是等待相同共享状态的读卡器所需。明白了。互斥体注释意味着只有一个东西可以与承诺交互以使状态就绪,而与注释同步意味着等待状态的任何东西都可以看到值。对,该互斥体(不必实际存在,只要实现的行为与实际相同)用于序列化对set_xxx函数的调用。共享状态上的大多数操作都要求是原子w.r.t读写器,但这是一个操作(或至少是“通过”)承诺。@TemplateRex,这似乎不是与此答案直接相关的注释。请参阅仅解释文档和回归修复的内容。对于严重的非回归错误或不构成破坏发布分支风险的琐碎修复(但不仅仅是因为有人ping它)可以例外。这完全符合主干上固定的内容不会自动固定在发布分支上的政策,因此您不应该对此感到惊讶。gcc 5的功能冻结是在2014年11月!该修复看起来很简单,但我不知道是否安全。
g++ --std=c++11 -Wall -g -o spin-wait spin-wait.cc -pthread
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <unistd.h>

int main() {
  bool done = 0;
  std::mutex m;
  std::condition_variable cv;

  std::thread t([&m, &cv, &done](){
    std::cout << "Biding my time in a thread.\n";
    sleep(10);
    {
      std::lock_guard<std::mutex> lock(m);
      done = 1;
    }
    cv.notify_all();
  });

  std::cout << "Waiting.\n";
  {
    std::unique_lock<std::mutex> lock(m);
    cv.wait(lock, [&done]{ return done; });
  }
  std::cout << "Done.\n";

  t.join();
  return 0;
}