web-dev-qa-db-fra.com

C ++ Mise en œuvre de la fonction de rappel chronométrée

Je souhaite mettre en œuvre un système en C++ afin que je puisse appeler une fonction et demander une autre fonction d'être appelée en x millisecondes. Quelque chose comme ça:

callfunctiontimed(25, funcName);

25 étant la quantité de millisecondes avant que la fonction soit appelée.

J'aimerais savoir si la multiplication est requise pour cela, puis utilisez une fonction de retard? Autre que d'utiliser le pointeur de fonction, comment une fonctionnalité comme ce travail serait-elle une fonctionnalité?

15
DavidColson

Beaucoup de gens ont contribué ici sur la question, mais je vais aborder la question directement, car j'avais un problème similaire il y a quelques années. Je ne pouvais pas utiliser boost pour plusieurs raisons - je sais que Boost a une excellente utilisation dans un grand logiciel open source. De plus, je voulais vraiment comprendre minuteries et rappels spécifiquement en ce qui concerne les environnements basés sur Linux. Alors, j'ai écrit le mien.

Fondamentalement, j'ai une classe Timer et une classe TimerCallback. Un rappel typique, mis en œuvre comme une classe hérité de la classe TimerCallback, placera les opérations à exécuter lors du rappel dans la méthode triggered (), mise en œuvre spécifiquement pour les besoins.

Par la sémantique habituelle, un objet Timer est associé à un objet de rappel, qui contient probablement toutes les informations requises nécessaires au rappel à exécuter. La programmation de la minuterie est gérée par une minuterie à l'échelle de l'environnement Minheap, qui doit être maintenue dans un thread/processus séparé. Cette tâche de Minheap ne fait qu'une seule chose: elle minime le minache des événements de rappel fixés dans le futur. Un Minheap sélectionne le prochain événement pour tirer dans O(1) et peut commercialiser le reste dans O(log n) pour n Evénements de minuterie. Il peut également insérer un nouvel événement de minuterie dans O(log n) (lire une introduction douce aux tas ici ).

Lorsqu'une minuterie incendie, le planificateur de Minheap vérifie s'il s'agit d'une minuterie périodique, d'une minuterie de tir ou d'une minuterie qui exécutera un nombre spécifique de fois. En conséquence, l'objet de la minuterie est soit retiré du Minheap, soit réinséré dans le Minheap avec le prochain temps d'exécution. Si un objet de minuterie doit être supprimé, il est supprimé du minache (mais la suppression de l'objet de la minuterie peut être laissée ou non à la tâche qui l'a créée) et le reste du tas est Minheap-ici; C'est-à-dire, réarrangé pour satisfaire la propriété Minheap.

Une implémentation de travail et testée unitaire est ici , et peut contenir des bugs (extrait de ma candidature), mais je pensais que cela pourrait aider quelqu'un. La mise en œuvre est multi-processus (fork() e-processus) basée sur (et utilise également pthreads dans la tâche principale (processus)) et utilise des files d'attente de mémoire partagée de POSIX et de messages POSIX pour la communication entre le processus.

6
Sonny

Pour une solution portable, vous pouvez utiliser Boost :: Asio. Ci-dessous est une démo que j'ai écrite il y a un moment. Vous pouvez changer

t.expires_from_now(boost::posix_time::seconds(1));

pour vous convenir, vous avez besoin de faire appel à la fonction après 200 millisiesondes.

t.expires_from_now(boost::posix_time::milliseconds(200)); 

Vous trouverez ci-dessous un exemple de travail complet. Il appelle à plusieurs reprises mais je pense que cela devrait être facile à appeler une seule fois en change un peu.

#include <iostream>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

using namespace boost::asio;
using namespace std;

class Deadline 
{
public:
    Deadline(deadline_timer &timer) : t(timer) {
        wait();
    }

    void timeout(const boost::system::error_code &e) {
        if (e)
            return;
        cout << "tick" << endl;
        wait();
    }

    void cancel() {
        t.cancel();
    }


private:
    void wait() {
        t.expires_from_now(boost::posix_time::seconds(1)); //repeat rate here
        t.async_wait(boost::bind(&Deadline::timeout, this, boost::asio::placeholders::error));
    }

    deadline_timer &t;
};


class CancelDeadline {
public:
    CancelDeadline(Deadline &d) :dl(d) { }
    void operator()() {
        string cancel;
        cin >> cancel;
        dl.cancel();
        return;
    }
private:
    Deadline &dl;
};



int main()
{
    io_service io;
    deadline_timer t(io);
    Deadline d(t);
    CancelDeadline cd(d);
    boost::thread thr1(cd);
    io.run();
    return 0;
}



//result:
//it keeps printing tick every second until you enter cancel and enter in the console
tick
tick
tick
17
Gob00st

Sous Windows, vous avez SetTimer - http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906 (v = vs.85) .aspx

Exemple de code:

#define STRICT 1 
#include <windows.h>
#include <iostream.h>

VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime) 
{




  cout << "CALLBACK " << dwTime << '\n';
  cout.flush();
}

int main(int argc, char *argv[], char *envp[]) 
{
    int Counter=0;
    MSG Msg;

    UINT TimerId = SetTimer(NULL, 0, 2000, &TimerProc); //2000 milliseconds

    cout << "TimerId: " << TimerId << '\n';
   if (!TimerId)
    return 16;

   while (GetMessage(&Msg, NULL, 0, 0)) 
   {
        ++Counter;
        if (Msg.message == WM_TIMER)
        cout << "Counter: " << Counter << "; timer message\n";
        else
        cout << "Counter: " << Counter << "; message: " << Msg.message << '\n';
        DispatchMessage(&Msg);
    }

   KillTimer(NULL, TimerId);
return 0;
}
2
Software_Designer