编辑:tl; dr - 此问题似乎仅限于一小组OS /编译器/库组合,现在由于{{3}而在GCC Bugzilla中以Bug 68921进行跟踪}。
我等待未来,我注意到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++
中的实现是那么糟糕?
答案 0 :(得分:9)
当然不应该这样做,这是实施中的错误,而不是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中修复
答案 1 :(得分:0)
不,它不应该。它通常效果很好。
(在评论中,我们试图确定更多关于特定的破坏配置,其中生成的可执行文件似乎旋转等待,但我相信这是答案。确定这是否仍然是一个很好的在最新的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
在更新promise对象时获取与promise对象关联的单个互斥锁。
虽然他们根据promise对象而不是共享状态描述同步有点令人不安,但意图非常明确。
cppreference.com [*]继续以完全不同于上述问题的方式使用它。 (“这个例子说明了如何将promise用作线程之间的信号。”)