web-dev-qa-db-fra.com

Comment rendre une fonction asynchrone en C++?

Je veux appeler une fonction qui sera asynchrone (je rappellerai lorsque cette tâche sera terminée).

Je veux faire cela en thread simple.

20
yogesh

Cela peut être fait de manière portable avec le C++ moderne ou même avec l'ancien C++ et certains boost . Boost et C++ 11 incluent des fonctionnalités sophistiquées pour obtenir des valeurs asynchrones à partir de threads, mais si vous souhaitez simplement un rappel, lancez simplement un thread et appelez-le.

Approche C++/boost 1998:

#include <iostream>
#include <string>
#include <boost/thread.hpp>
void callback(const std::string& data)
{
    std::cout << "Callback called because: " << data << '\n';
}
void task(int time)
{
    boost::this_thread::sleep(boost::posix_time::seconds(time));
    callback("async task done");
}
int main()
{
    boost::thread bt(task, 1);
    std::cout << "async task launched\n";
    boost::this_thread::sleep(boost::posix_time::seconds(5));
    std::cout << "main done\n";
    bt.join();
}

Approche C++ 2011 (utilisant gcc 4.5.2, qui a besoin de cette #define)

#define _GLIBCXX_USE_NANOSLEEP
#include <iostream>
#include <string>
#include <thread>
void callback(const std::string& data)
{
    std::cout << "Callback called because: " << data << '\n';
}
void task(int time)
{
    std::this_thread::sleep_for(std::chrono::seconds(time));
    callback("async task done");
}
int main()
{
    std::thread bt(task, 1);
    std::cout << "async task launched\n";
    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "main done\n";
    bt.join();
}
15
Cubbi

Vous ne pouvez pas en clair C++. Vous devrez utiliser un mécanisme spécifique au système d'exploitation et un point où l'exécution est suspendue de manière à ce que le système d'exploitation puisse exécuter le rappel. Par exemple. pour Windows, QueueUserAPC - le rappel est exécuté lorsque, par exemple, vous SleepEx ou WaitForSingleObjectEx

5
Erik

La réponse longue consiste à implémenter votre propre planificateur de tâches et à intégrer votre "fonction" à une ou plusieurs tâches. Je ne suis pas sûr que vous vouliez la réponse longue. Cela ne vous permet certainement pas d’appeler quelque chose, de l’oublier complètement, puis d’être averti lorsque cette chose est faite; Toutefois, si vous vous sentez ambitieux, cela vous permettra de simuler des coroutines à un niveau donné sans dépasser les normes C++ standard.

La réponse courte est que ce n'est pas possible. Utilisez plusieurs threads ou plusieurs processus. Je peux vous donner des informations plus spécifiques si vous divulguez le système d'exploitation/la plate-forme que vous développez.

3
Ken Rockot

Cela fait deux choses. 

Tout d’abord, préparer l’appel de fonction pour qu’il puisse être exécuté ultérieurement.

Deuxièmement, la planification.

C'est la planification qui dépend d'autres aspects de la mise en œuvre. Si vous savez "quand cette tâche est terminée", alors il ne vous reste plus qu'à revenir en arrière et récupérer "l'appel de fonction" et l'appeler. Donc, je ne suis pas sûr que ce soit nécessairement un gros problème.

La première partie concerne alors réellement les objets de fonction, voire les pointeurs de fonction. Ces derniers sont le mécanisme de rappel traditionnel de C.

Pour un FO, vous pourriez avoir:

class Callback
{
public:
  virtual void callMe() = 0;
};

Vous en dérivez et implémentez-le comme vous le souhaitez pour votre problème spécifique. La file d'attente d'événements asynchrones n'est alors rien d'autre qu'un list<> de rappels:

std::list<Callback*> asyncQ; // Or shared_ptr or whatever.
3
Keith

Je ne suis pas sûr de comprendre ce que vous voulez, mais si c'est comment utiliser un rappel: Cela fonctionne en définissant un pointeur de fonction, comme ceci (non testé):

// Define callback signature.
typedef void (*DoneCallback) (int reason, char *explanation);

// A method that takes a callback as argument.
void doSomeWorkWithCallback(DoneCallback done)
{
    ...
    if (done) {
       done(1, "Finished");
    }   
}

//////

// A callback
void myCallback(int reason, char *explanation)
{
    printf("Callback called with reason %d: %s", reason, explanation);
}

/////

// Put them together
doSomeWortkWithCallback(myCallback);
1
DarkDust

Comme d'autres l'ont dit, techniquement, vous ne pouvez pas utiliser du C++ simple. 

Cependant, vous pouvez créer un gestionnaire qui s'acquitte de votre tâche et effectue le découpage ou la planification du temps; à chaque appel de fonction, le gestionnaire utilise un minuteur pour mesurer la durée du processus; si le processus a pris moins de temps que prévu et qu'il pense pouvoir terminer un autre appel et utiliser le temps restant sans dépasser, il peut le rappeler; si la fonction dépasse le temps alloué, cela signifie que la prochaine mise à jour de la fonction a moins de temps. Donc, cela impliquera de créer un système quelque peu complexe pour le gérer pour vous.

Ou, si vous avez une plate-forme spécifique à l'esprit, vous pouvez utiliser le threading ou créer un autre processus pour gérer le travail. 

0
leetNightshade