Search code examples
multithreadingc++11c++-chronolong-long

C++ Chrono - How to use the duration_cast on std::atomic<long long>?


I'm have a class Bar with:

class Bar
{
public:
    //...
private:
    std::atomic<long long>          m_keepAlive;
}

This class have some methods described below.

This method gets the epoch in ms:

long long Bar::getTimeSinceEpoch()
{
    std::chrono::time_point<std::chrono::system_clock> p = std::chrono::system_clock::now();
    const long long epoch = std::chrono::duration_cast<std::chrono::milliseconds>(p.time_since_epoch()).count();
    return epoch;
}

This method is being called from another thread and updates my m_keepAlive.

void Bar::keepAlive() //This method is being called from other thread
{
    m_keepAlive= getTimeSinceEpoch();
}

On my Bar class, I have a method that keeps calling this checkKeepAlive() method and checks if 2 seconds has passed, since the last time Bar::keepAlive() was executed.

void Bar::checkKeepAlive()
{
    auto now = std::chrono::system_clock::now();

   //COMPILATION ERROR here
    auto difference = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_keepAlive); 

    auto timeMsSinceNoReply = difference.count();

    if(timeMsSinceNoReply >= 2000)
    {
        //timeout
    }
}

To acomplish this, I've created the std::atomic<long long> to be thread safe on my class.

However, I get this compilation error:

no match for ‘operator-’ (operand types are ‘std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1l, 1000000000l> > >’ and ‘long long int’)

How can I use the duration_cast on std::atomic<long long>?


Solution

  • The chrono library is build in order to keep you explicit and type safe, by using all the calls to std::chrono::duration::count you are abusing library.

    now - m_keepAlive is illegal in your example. Your compiler tells you this.

    • now is of type std::chrono::system_clock::time_point.
    • m_keepAlive is of type std::atomic<long long>.

    Even if you change m_keepAlive to long long, it will still not work.

    You need to convert m_keepAlive to a duration, before you try to subtract it from now.

    For instance: std::chrono::milliseconds(m_keepAlive.load()) will interpret the value kept by m_keepAlive as a number of milliseconds.

    Full expression should be: const auto difference = now - std::chrono::system_clock::time_point(std::chrono::milliseconds(m_keepAlive.load());

    Then use as follows: if(difference >= std::chrono::seconds(2)) { ... }