1

There is such an interesting little code (I'll take the most important thing, since my project is quite large

        void RunForever(int time_out)
        {
            int criticalSize = 3;
            size_t size_sheldure = PopSheldure();

            while (isRunning)
            {
                if (size_sheldure < criticalSize)
                    UpdateScheldure(0);

                auto lineScheldure = (*(m_scheldure)).front();

                m_radioConnector.UpdateParametersRadio(lineScheldure);

                ptime near_future = from_iso_string(lineScheldure.GetUTCTime()); 
                ptime current_time = ComputeCurrentLocalTime();

                std::cout << ((near_future - current_time).total_seconds()) << std::endl;

                if ((near_future - current_time).total_seconds() < 0)
                {
                    PopSheldure();
                    continue;
                }

                m_timer.expires_after(boost::asio::chrono::seconds(time_out));
                m_timer.async_wait([this](const boost::system::error_code& ec)
                {
                    if (!ec)
                    {
                        std::lock_guard<std::mutex> lock(mtx);
                        isTimerFinish = true;
                    }
                    cv_isListen.notify_one();
                    std::cout << "Timer finished" << std::endl;
                });

                if (lineScheldure.GetStatusInfo() == BasicDefinition::RadioStatus::Listen)
                    StartListenSession(time_out);

                if (lineScheldure.GetStatusInfo() == BasicDefinition::RadioStatus::Send)
                    StartSendSession(time_out);

                size_sheldure = PopSheldure();
            }
        }

There are also two functions that are called depending on the current status:

        void StartSendSession(int time_out)
        {
            auto sendHandler = std::bind(&ModemConnector::SendHandler, this, std::placeholders::_1);
            if (m_modem)
            {

            }
            std::unique_lock<std::mutex> lock(mtx);
            cv_isSend.wait(lock);
            isTimerFinish = false;

            std::cout << "Send --> Listen" << std::endl;
        }
        void StartListenSession(int time_out)
        {
            if (m_modem)
            {

            }

            std::unique_lock<std::mutex> lock(mtx);
            std::cout << "Check" << std::endl;
            cv_isListen.wait(lock);

            isTimerFinish = false;
            std::cout << "Listen --> Send" << std::endl;
        }

The problem is that sending and receiving is done on a timer. When the timer ends, I need the thread to continue executing, but in reality, usually starting from the second timer, one of the functions gets stuck. What is the reason for this behavior of functions?

output

1 
Check
Timer finished
Listen --> Send
2
Timer finished
3
  • 2
    never wait on a condition variable without a predicate, if the event happens before the wait then you will be stuck forever, add a predicate to every .wait , most IDEs have a something like ctrl + shift + f to find something in all files, search for .wait( and for all results you find make sure it has 2 arguments where the second one is a predicate.
    – Ahmed AEK
    Commented Jan 25 at 8:02
  • the predicate can be as simple as waiting for a bool to become true, that's close to what other languages have Event objects for, a condition_variable is more low-level than that. it is used to build other primitives like the Event
    – Ahmed AEK
    Commented Jan 25 at 8:14
  • Also, signal under the mutex, so you get fair scheduling guarantees (otherwise some threads may starve)
    – sehe
    Commented Jan 25 at 20:40

1 Answer 1

0

usually starting from the second timer, one of the functions gets stuck. What is the reason for this behavior of functions?

From your code it looks like the same timer is being re-used always. However, this

 m_timer.expires_after(boost::asio::chrono::seconds(time_out));

cancels any timer still pending. In your completion handler, you only check if (!ec) which means that on a canceled timer you do NOT set isTimerFinish.

Something tells me you can greatly simplify this design, but it's not possible to make concrete suggestions without the rest of the code.

1
  • I have solved the problem. The problem was the lack of a valid predicate. The local variable was checked. The tangent of the timer is std::optinal -> in main, I initialize this timer using io_context. Each iteration, it was restarted, and lambda was triggered. In my code, the timer is not canceled at the moment. In the future, I will implement this functionality as well. In my code, the timer is not canceled at the moment. I will also implement functionality for canceled timers. Most likely, in case of an error, I will recursively recreate the timer for a different time.st it.Thank you! Commented Jan 25 at 21:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.