Partage
  • Partager sur Facebook
  • Partager sur Twitter

Multhreading Chronometer

Comportement hasardeux sur les threads

    3 septembre 2021 à 17:33:23

    Bonjour à tous,

    Je suis nouveau dans les threads et j'aurai besoin d'un petit coup de pouce car il se passe des choses étranges dans l’exécution de mon code.

    Voici mon code

    mychrono.cpp

    #include "mychrono.hpp"
    #include <thread>
    
    
    Chronometer::Chronometer()
    {
        thread.reset(new std::thread(&Chronometer::thread_function, this));
    }
    
    void Chronometer::start_chrono()
    {
        thread.reset(new std::thread(&Chronometer::thread_function, this));
    }
    
    void Chronometer::reset_chrono()
    {
        std::lock_guard<std::mutex> lock(timeMutex);
    
        currentTime.hour = 0;
        currentTime.sec = 0;
        currentTime.min = 0;
    }
    
    std::ostream& operator<<(std::ostream& flux, Chronometer& t)
    {
        flux << t.to_string();
        return flux;
    }
    
    Chronometer& Chronometer::operator=(const Chronometer& other)
    {
        // Guard self assignment
        //if (this == &other)
        return *this;
    }
    
    std::string Chronometer::to_string()
    {
        std::lock_guard<std::mutex> lock(timeMutex);
    
        return std::to_string(currentTime.hour) + ":" + std::to_string(currentTime.min) + ":" + std::to_string(currentTime.sec);
    }
    
    Chronometer::Time Chronometer::get_time()
    {
        return currentTime;
    }
     
    Chronometer::~Chronometer()
    {
        exitNow = true;
        
        {
            std::unique_lock<std::mutex> lock(CVMutex);
    
            lock.unlock();
            conditionVariable.notify_all();
        }
    
        thread->join();
    }
    
    void Chronometer::thread_function()
    {
        std::unique_lock<std::mutex> waitLock(CVMutex);
    
        while(!exitNow)
        {
            currentTime.sec++;
     
            if(currentTime.sec > 59) {
                std::lock_guard<std::mutex> lock(timeMutex);
    
                currentTime.min++;
                currentTime.sec = 0;
            }
     
            if(currentTime.min > 59) {
                std::lock_guard<std::mutex> lock(timeMutex);
    
                currentTime.hour++;
                currentTime.sec = 0;
                currentTime.min = 0;
            }
    
            //std::cout << "chrono: " << *this << std::endl; //Not thread safe be careful
    
            conditionVariable.wait_for(waitLock, std::chrono::seconds(1));
        }
    }
    

    mychrono.hpp

    #ifndef mychrono_hpp
    #define mychrono_hpp
     
    
    #include <iostream>
    #include <thread>
    #include <memory>
    #include <condition_variable>
    #include <mutex>
    #include <atomic>
     
    class Chronometer
    {
        public:
            struct Time {
                int hour;
                int min;
                int sec;
            };
    
            Chronometer();
            void start_chrono();
            void reset_chrono();
            friend std::ostream& operator<<(std::ostream& flux, Chronometer& t);
            Chronometer& operator=(const Chronometer& other);
            std::string to_string();
            Time get_time();
            ~Chronometer();
    
         private:
            Time currentTime = {0,0,0};
            std::mutex timeMutex;
            std::condition_variable conditionVariable;
            std::unique_ptr<std::thread> thread;
            std::mutex CVMutex;
            std::atomic<bool> exitNow;
    
            void thread_function();
    };
     
    #endif
    

    Et en fin le main:

    test.cpp

    #include <iostream>
    #include <vector>
    #include <unistd.h>
    
    #include <opencv2/highgui.hpp>
    #include "opencv2/video/video.hpp"
    #include <opencv2/imgproc.hpp>
    #include <opencv2/videoio/videoio.hpp>
    #include <opencv2/imgcodecs/imgcodecs.hpp>
    
    #include "mychrono.hpp"
    
    int main()
    {
        std::vector<Chronometer*> car_crono;
        int compt(0);
    
        // for(int i = 0; i < 2; i++)
        // {
        //     car_crono.push_back(new Chronometer);
        // }
    
        //car_crono.push_back(new Chronometer);
    
        cv::VideoCapture cap("rtsp://192.168.1.56:10001/20210818_113229_resize.264");
    
        while (1) {
    
            // cv::Mat frame;
            // cap >> frame;
    
            // if (frame.empty()) {
            //     break;
            // }
           std::cout << "compt: " << compt << std::endl;
           compt++;
            sleep(4);
    
            if(compt == 3){car_crono.push_back(new Chronometer);}
    
             if(car_crono.size() != 0)  
             {
                Chronometer::Time t = car_crono[0]->get_time();
    
                if(t.sec >= 10)
                    car_crono[0]->reset_chrono();
    
                std::cout << "Seconds of T0: " << t.sec << std::endl;
                std::cout << "T1: " << car_crono[0]->to_string() << std::endl;
    
                std::cout << "hello-world" << std::endl;
                std::cout << "car_crono.size(): " << car_crono.size() << std::endl;
                sleep(4);
             }
    
            //  cv::imshow("output", frame);
    
    		// if(cv::waitKey(10) == 27)
    		// {
    		// 	std::cout << "Esc key is pressed by user. Stopping the video" << std::endl;
    		// 	break;
    		// }                
            
        }
    
        car_crono.clear();
    }
    
    

    Lorsque j'exécute le code je démarre un chrono après 12 secondes de temps puis le chrono s'affiche toutes les 8 secondes. J'avais déjà testé mes chronos et lorsque j'en instanciais un ou plusieurs ils fonctionnaient parfaitement. Mais en les utilisant dans d'autres programmes je me rends compte que les chronos se comportent de façon étrange (chrono restant à 0, ou s'incrémentent correctement puis revienne à 0 sans raison). Dans d'autres programmes j'utilise opencv et si vous faites les tests opencv (code test.cpp plus haut) influe sur mes chronos sans raison apparente. Si quelqu'un a une idée de ce drôle de comportement je veux bien un éclaircissement.




    • Partager sur Facebook
    • Partager sur Twitter
      6 septembre 2021 à 23:48:54

      Lignes 45-46, ton code réinitialise le chronomètre après 10 secondes, donc ça paraît normal. 

      Par contre, avec wait_for, ton chronomètre dérive avec le temps, puisque au temps d'attente, il faut ajouter le temps d'exécution du code en dehors de l'attente. Pour éviter ça tu devrais utiliser wait_until: 

      void Chronometer::thread_function()
      {
          std::unique_lock<std::mutex> waitLock(CVMutex);
          auto lastTime = std::chrono::steady_clock::now();
      
          while(!exitNow)
          {
             ...
         
            conditionVariable.wait_until(waitLock, lastTime + std::chrono::seconds(1));
            lastTime+=std::chrono::seconds(1);
          }
      }    
      • Partager sur Facebook
      • Partager sur Twitter

      Multhreading Chronometer

      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
      • Editeur
      • Markdown