28 votes

Est-ce que std :: future :: wait devrait utiliser autant de CPU? Y a-t-il un appel plus performant?

EDIT: tl;dr -- ce problème semble être limité à un petit ensemble de OS/compilateur/bibliothèque de combinaisons et est maintenant suivie dans le GCC Bugzilla comme Bug 68921 grâce à @JonathanWakely.

Je suis en attente sur un avenir, et j'ai remarqué qu' top montre 100% d'utilisation du PROCESSEUR et de la strace montre un flux régulier de futex appels:

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

C'est sur Linux 4.2.0 (32 bits i686), compilé avec gcc version 5.2.1.

Ici, c'est mon minimum viable exemple de programme:

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

et voici le compilateur invocation (même comportement sans -g):

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

Est-il plus performant alternative?

Voici une logique similaire de programme à l'aide de std::condition_variable qui semble fonctionner beaucoup mieux:

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

Suis-je en train de faire quelque chose de mal avec mon std::future-en fonction du code, ou est la mise en œuvre dans mon libstdc++ juste que mauvais?

9voto

Jonathan Wakely Points 45593

Non bien sûr, il ne faut pas faire ça, c'est un bug dans la mise en œuvre, et non pas une propriété de l' std::future.

C'est maintenant https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68921 - la boucle qui continue d'appeler, futex(2) est __atomic_futex_unsigned::_M_load_and_test_until

Il ressemble à un simple argument manquant à l' syscall fonction, de sorte qu'une poubelle pointeur est transmis au noyau, qui se plaint qu'il n'est pas valide timespec* argument. Je suis en essais de la correction et de commettre demain, de sorte qu'il sera résolu dans GCC 5.4

0voto

Rob Starling Points 1565

Non, il ne devrait pas. Habituellement, il fonctionne très bien.

(Dans les commentaires, nous essayons de déterminer plus précises cassé la configuration dans laquelle la résultante exécutable semble spin-attendez, mais je crois que c'est la réponse. Il serait encore belle pour déterminer si c'est encore un spin-attendre sur une cible 32 bits dans le dernier g++.)

La promesse est le "pousser" à la fin de la promesse-l'avenir du canal de communication: l'opération qui stocke une valeur dans l'état partagé synchronise avec (tel que défini en std::memory_order) le retour réussi de toute fonction qui est en attente sur l'état partagé (comme std::future::get).

Je suppose que cela inclut std::future::wait.

[std::promise::set_value] Atomiquement stocke la valeur dans l'état partagé et donne à l'état prêt. L'opération se comporte comme s' set_value, set_exception, set_value_at_thread_exit, et set_exception_at_thread_exit acquérir une seule mutex associé avec la promesse de l'objet alors que la mise à jour de la promesse de l'objet.

Alors que c'est un peu déstabilisant qu'ils décrivent la synchronisation dans les termes de la promesse de l'objet et non l'partagée-état, l'objectif est assez clair.

cppreference.com[*] continue à utiliser exactement de la façon que ça ne marchait pas dans la question ci-dessus. ("Cet exemple montre comment la promesse peut être utilisé comme des signaux entre les threads.")

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X