std::future::wait 应该使用这么多 CPU 吗?是否有性能更高的调用
Should std::future::wait be using so much CPU? Is there a more performant call?
编辑: tl;dr -- 这个问题似乎仅限于一小部分操作系统/编译器/库组合,现在在 GCC Bugzilla 中被跟踪为 Bug 68921,这要归功于@JonathanWakely。
我正在等待未来,我注意到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;
}
这是编译器调用(没有-g
的相同行为(:
g++ --std=c++11 -Wall -g -o spin-wait spin-wait.cc -pthread
有没有性能更高的替代方案?
这是一个逻辑上相似的程序,使用 std::condition_variable
似乎性能更好:
#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;
}
我是否对基于 std::future
的代码做错了什么,或者我的libstdc++
中的实现是否那么糟糕?
不,当然不应该这样做,这是实现中的一个错误,而不是std::future
的属性。
现在 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68921 - 不断调用futex(2)
的循环处于__atomic_futex_unsigned::_M_load_and_test_until
它看起来像是 syscall
函数的简单缺失参数,因此将垃圾指针传递给内核,内核抱怨它不是一个有效的timespec*
参数。我正在测试修复程序,明天将提交,因此它将在GCC 5.4中修复
不,不应该。它通常效果很好。
(在评论中,我们试图确定更多关于特定损坏配置的信息,其中生成的可执行文件似乎在旋转等待,但我相信这就是答案。确定这是否仍然是最新 g++ 中 32 位目标的旋转等待仍然很好。
promise是promise-future通信通道的"推送"端:在共享状态下存储值的操作与(如
std::memory_order
中所定义(从等待共享状态的任何函数(如std::future::get
(的成功返回同步。
我认为这包括std::future::wait
.
[
std::promise::set_value
] 以原子方式将值存储到共享状态中,并使状态准备就绪。 该操作的行为就像set_value
、set_exception
、set_value_at_thread_exit
,并且在更新承诺对象时set_exception_at_thread_exit
获取与承诺对象关联的单个互斥锁。
虽然他们用承诺对象而不是共享状态来描述同步有点令人不安,但意图非常明确。
cppreference.com[*] 继续以在上述问题中不起作用的方式使用它。("这个例子展示了 promise 如何用作线程之间的信号。
- 是否总是可以将使用递归编写的程序重写为不使用递归的程序C++,性能观点是什么?
- 不同版本的编译器(例如GCC)是否会产生不同的性能?
- 在现代C++中,侵入式容器是否仍然比非侵入式容器具有性能优势?
- 与纯 V8 相比,NodeJS 是否有任何性能缺陷或显著开销?
- 通过默认复制构造函数比较 C++ 字符串是否会影响性能,原因为何?
- 隐式转换函数的返回对象时是否会影响性能?
- 为数组赋值时是否存在性能差异
- 在类中始终使用此指针是否有任何性能成本
- 在渲染之前直接上传是否会对性能产生负面影响
- 我是否错过了什么,或者虚拟呼叫的性能并不像人们所说的那样糟糕
- 使用 OpenGL 窗口(如 GLFW)或周围的窗口(如 GTK 或 SDL)是否存在性能差异?
- 在将其尺寸较大的向量移动到容量较小的向量之前,是否可以通过使用Reserve()来提高代码性能
- QSqlQuery 绑定值与 BindValues 与 QString.arg() 是否存在性能差异
- 检查从查询返回的任何行是否包含在字符串中的最高性能方法?
- 在C++代码中使用纯 C 库是否有性能下降/损失
- 使用 const CString& 而不是单独使用 CString 作为函数参数是否有任何性能优势?
- 在 C/C++ 中在特定地址边界上对齐内存是否仍能提高 x86 性能?
- 是否有更好的方法(性能提高 /内置功能)获得矩形的旋转角度
- 在较大的架构上使用UINT8_T时,是否存在性能问题
- 对小型任务多次使用std::async是否性能友好