web-dev-qa-db-fra.com

besoin d'appeler une fonction à des intervalles de temps périodiques en c ++

J'écris un programme en c ++ où j'ai besoin d'appeler une fonction à intervalles de temps périodiques, disons toutes les 10 ms environ. Je n'ai jamais rien fait concernant le temps ou les horloges en c ++, est-ce un problème rapide et facile ou l'un de ceux où il n'y a pas de solution soignée?

Merci!

18
Execut1ve

Une minuterie simple peut être implémentée comme suit,

#include <iostream>
#include <chrono>
#include <thread>
#include <functional>

void timer_start(std::function<void(void)> func, unsigned int interval)
{
    std::thread([func, interval]() {
        while (true)
        {
            func();
            std::this_thread::sleep_for(std::chrono::milliseconds(interval));
        }
    }).detach();
}


void do_something()
{
    std::cout << "I am doing something" << std::endl;
}

int main() {
    timer_start(do_something, 1000);

    while(true);
}

Cette solution simple n'offre pas de moyen d'arrêter le chronomètre. La minuterie continuera de fonctionner jusqu'à la fin du programme.

17
user534498

Pour compléter la question, le code de @ user534498 peut être facilement adapté pour avoir l'intervalle de tick périodique. Il est juste nécessaire de déterminer le prochain point de départ au début de la boucle de thread du minuteur et sleep_until ce point temporel après l'exécution de la fonction.

#include <iostream>
#include <chrono>
#include <thread>
#include <functional>

void timer_start(std::function<void(void)> func, unsigned int interval)
{
  std::thread([func, interval]()
  { 
    while (true)
    { 
      auto x = std::chrono::steady_clock::now() + std::chrono::milliseconds(interval);
      func();
      std::this_thread::sleep_until(x);
    }
  }).detach();
}

void do_something()
{
  std::cout << "I am doing something" << std::endl;
}

int main()
{
  timer_start(do_something, 1000);
  while (true)
    ;
}
15
florgeng

Désolé, mais je n'ai pas trouvé de design plus simple que ça.

Vous pouvez créer une classe qui possède à la fois un thread et un weak_ptr à lui-même, pour être un "détenteur" que l'appelable peut le voir en toute sécurité, car l'appelable existera toujours même si l'objet est détruit. Vous ne voulez pas d'un pointeur suspendu.

template<typename T>
struct IntervalRepeater {
    using CallableCopyable = T;
private:
    weak_ptr<IntervalRepeater<CallableCopyable>> holder;
    std::thread theThread;

    IntervalRepeater(unsigned int interval,
            CallableCopyable callable): callable(callable), interval(interval) {}

    void thread() {
        weak_ptr<IntervalRepeater<CallableCopyable>> holder = this->holder;
        theThread = std::thread([holder](){
            // Try to strongify the pointer, to make it survive this loop iteration,
            //    and ensure that this pointer is valid, if not valid, end the loop.
            while (shared_ptr<IntervalRepeater<CallableCopyable>> ptr = holder.lock()) {
                auto x = chrono::steady_clock::now() + chrono::milliseconds(ptr->interval);
                ptr->callable();
                this_thread::sleep_until(x);
            }
        });
    }

public:
    const CallableCopyable callable;
    const unsigned int interval;

    static shared_ptr<IntervalRepeater<T>> createIntervalRepeater(unsigned int interval,
            CallableCopyable callable) {
        std::shared_ptr<IntervalRepeater<CallableCopyable>> ret =
                shared_ptr<IntervalRepeater<CallableCopyable>>(
                        new IntervalRepeater<CallableCopyable>(interval, callable));
        ret->holder = ret;
        ret->thread();

        return ret;
    }

    ~IntervalRepeater() {
        // Detach the thread before it is released.
        theThread.detach();
    }

};

void beginItWaitThenDestruct() {
    auto repeater = IntervalRepeater<function<void()>>::createIntervalRepeater(
            1000, [](){ cout << "A second\n"; });
    std::this_thread::sleep_for(std::chrono::milliseconds(3700));
}

int main() {
    beginItWaitThenDestruct();
    // Wait for another 2.5 seconds, to test whether there is still an effect of the object
    //   or no.
    std::this_thread::sleep_for(std::chrono::milliseconds(2500));
    return 0;
}
0
user9335240

Vous pouvez examiner le filetage:

Voici une fonction contrôlée par intervalle de temps implémentée en C, en utilisant pthread.h, elle devrait être un simple port vers C++. Exécution d'une fonction à des intervalles spécifiques

0
JMercer

C'est un article assez ancien mais j'ai trouvé une solution très simple à cela et je voudrais le partager:

la solution est de

#include "unistd.h"

et utiliser la fonction qui est incluse dans la bibliothèque ci-dessus,

usleep(int) 

par exemple, cela appellerait une fonction toutes les 3000 microsecondes

int main() {

    int sleep_time = 3000;
    while(true) { 

          usleep(sleep_time);

          call function;
    }

    return 0;
}

Je l'ai également utilisé pour les codes série et parallèle et fonctionne dans les deux cas!

0

Si vous codez avec Visual C++, vous pouvez ajouter un élément timer au formulaire que vous souhaitez appeler une fonction périodique (ici, cela s'appelle mon formulaire est MainForm, et mon timer MainTimer). Ajoutez un appel à l'événement tick dans les "Événements". Le concepteur ajoutera une telle ligne dans votre fichier .h:

this->MainTimer->Enabled = true;
this->MainTimer->Interval = 10;
this->MainTimer->Tick += gcnew System::EventHandler(this, &MainForm::MainTimer_Tick);

Ensuite, à chaque intervalle (spécifié en ms), l'application appellera cette fonction

private: System::Void MainTimer_Tick(System::Object^  sender, System::EventArgs^  e) {
   /// Enter your periodic code there
}
0
RawBean

Cela dépend de ce que vous feriez par intervalle - affichage de l'heure/du téléscripteur ou autre chose à un emplacement spécifique de l'écran/du formulaire. Ou vous devrez peut-être envoyer des données régulières à une machine connectée (via une prise ou un tuyau). Avez-vous vraiment besoin d'une précision de 10 millisecondes?

Selon l'exigence, en particulier l'exigence de précision, vous pouvez avoir un thread dédié à faire 'quelque chose', puis attendre et refaire la même chose. Ou, sous Windows, vous pouvez utiliser SetTimer qui déclencherait WM_TIMER événement sur chaque intervalle (il ne nécessiterait pas de thread). Vous pouvez également utiliser une minuterie d'attente, une minuterie multimédia, etc.

Enfin, mais assez important - Avez-vous besoin de la compatibilité de la plateforme et du compilateur? Autrement dit, quel système d'exploitation utiliseriez-vous ou avez-vous besoin d'une plate-forme indépendante? Quelles sont les fonctionnalités du compilateur que vous recherchez (C++ 11, C++ 14 ou pré C++ 11).

0
Ajay