Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should std::future::wait be using so much CPU? Is there a more performant call?

EDIT: tl;dr -- this problem appears to be limited to a small set of OS/compiler/library combinations and is now tracked in the GCC Bugzilla as Bug 68921 thanks to @JonathanWakely.

I'm waiting on a future and I've noticed that top shows 100% CPU usage and strace shows a steady stream of futex calls:

... [pid 15141] futex(0x9d19a24, FUTEX_WAIT, -2147483648, {4222429828, 3077922816}) = -1 EINVAL (Invalid argument) ... 

This is on Linux 4.2.0 (32-bit i686), compiled with gcc version 5.2.1.

Here is my minimum-viable example program:

#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; } 

and here is the compiler invocation (same behavior without -g):

g++ --std=c++11 -Wall -g -o spin-wait spin-wait.cc -pthread 

Is there a more-performant alternative?

Here is a logically-similar program using std::condition_variable that seems to perform much better:

#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; } 

Am I doing something wrong with my std::future-based code, or is the implementation in my libstdc++ just that bad?

like image 834
Rob Starling Avatar asked Dec 14 '15 03:12

Rob Starling


People also ask

Is std :: future thread safe?

std::shared_futureAccess to the same shared state from multiple threads is safe if each thread does it through its own copy of a shared_future object.

What is std :: future in C++?

std::future A future is an object that can retrieve a value from some provider object or function, properly synchronizing this access if in different threads. "Valid" futures are future objects associated to a shared state, and are constructed by calling one of the following functions: async. promise::get_future.


1 Answers

No of course it shouldn't be doing that, it's a bug in the implementation, not a property of std::future.

This is now https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68921 - the loop that keeps calling futex(2) is in __atomic_futex_unsigned::_M_load_and_test_until

It looks like a simple missing argument to the syscall function, so a garbage pointer is passed to the kernel, which complains that it's not a valid timespec* argument. I'm testing the fix and will commit tomorrow, so it will be fixed in GCC 5.4

like image 153
Jonathan Wakely Avatar answered Sep 20 '22 17:09

Jonathan Wakely