Race Condition



  • folgender Code ist bei parallelen Aufrüfen von "start" nicht threadsicher. Ich habe alles auskommentiert, was nichts mit dem Fehler zu tun hat.

    Wenn ich

    pulser_ = std::thread {/*...*/};
    

    auskommentiere ist der Fehler weg.

    Mein "if running, stop, restart" muss falsch und nicht atomar sein.

    aber dabei ist doch nur noch std::thread, std::atomic_bool und ein lambda über nach dem ich alles auskommentiert habe.
    Was ist hier broken?

    //---------------------------------------------------------------------------------------------------------------------
        void Controller::start()
        {
            if (running_.load() == true)
                pause();
    
            pulser_ = std::thread
            {
                [this]()
                {
                    running_.store(true);
    
                    try
                    {
                        //auto lastRefreshTime = std::chrono::system_clock::now();
                        //refreshAllCloners();
    
                        for (;running_.load();)
                        {
                            std::this_thread::sleep_for(std::chrono::milliseconds(50));
    
                            /*
                            bool workDone = pulseAllCloners();
    
                            if (!workDone)
                                std::this_thread::sleep_for(std::chrono::milliseconds(50));
    
                            // look for new files in system
                            if (std::chrono::system_clock::now() - lastRefreshTime > std::chrono::milliseconds(interval_))
                            {
                                refreshAllCloners();
                                lastRefreshTime = std::chrono::system_clock::now();
                            }
                            */
                        }
                    }
                    catch (std::exception const& exc)
                    {
                        running_.store(false);
                        //lastError_ = exc.what();
                    }
                }
            };
        }
    //---------------------------------------------------------------------------------------------------------------------
        void Controller::pause()
        {
            running_.store(false);
            if (pulser_.joinable())
                pulser_.join();
        }
    //---------------------------------------------------------------------------------------------------------------------
    

    Head:

    std::thread pulser_;
    std::atomic_bool running_;
    

    (Der Fehler veräußert sich übrigens so:)

    terminate called without an active exception

    terminate called recursively

    terminate called recursively

    terminate called recursively

    Oder (selten) gefangen an anderer stelle (std::exception::what):

    no such process



  • update:
    Das hier reicht für die start methode:

    void Controller::start()
    {
        // auch keine Lösung
        // std::lock_guard <std::mutex> x (startLock_);
    
        if (running_.load() == true)
            pause();
    
        pulser_ = std::thread
        {
            [this]()
            {
                running_.store(true);
                std::this_thread::sleep_for(std::chrono::milliseconds(50));
            }
        }
    }
    //---------------------------------------------------------------------------------------------------------------------
    void Controller::pause()
    {
        running_.store(false);
        if (pulser_.joinable())
            pulser_.join();
    }
    


  • Hab die Lösung:

    void Controller::start()
    {
        pause(); 
        pulser_ = std::thread
        {
            [this]()
            {
                running_.store(true);
                std::this_thread::sleep_for(std::chrono::milliseconds(50));
            }
        }
    }
    //---------------------------------------------------------------------------------------------------------------------
    void Controller::pause()
    {
        running_.store(false);
        if (pulser_.joinable())
            pulser_.join();
    }
    

    (Edit: Der Thread wurde assigned, while joinable -> terminate() wird aufgerufen)