C ++ ThreadSafe класс подсчета времени - PullRequest
0 голосов
/ 28 декабря 2018

Я пытаюсь создать простой потокобезопасный счетчик времени.Код, который мне удалось написать, выглядит следующим образом:

#include <iostream>
#include <chrono>
#include <mutex>
#include <condition_variable>

/* Get timestamp in microseconds */
static inline uint64_t micros()
{
    return (uint64_t)std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
}

class Timer
{
public:
    explicit Timer() = default;


    /**
     * @brief Restart the counter
     */
    void Restart()
    {
        std::unique_lock<std::mutex> mlock(_mutex);
        {
            this->_PreviousUs = micros();
            this->_IsRunning = true;
        }
        mlock.unlock();
        _cond.notify_one();
    }

    /**
     * @brief Stop the timer
     */
    void Stop()
    {
        std::unique_lock<std::mutex> mlock(_mutex);
        {
            this->_IsRunning = false;
        }
        mlock.unlock();
        _cond.notify_one();
    }


    /**
     * @brief Check whether counter is started or not
     * @return true if timer is running, false otherwise
     */
    bool IsRunning()
    {
        std::unique_lock<std::mutex> mlock(_mutex);
        bool tmp = _IsRunning;
        mlock.unlock();
        _cond.notify_one();
        return tmp;
    }

    /**
     * @brief Calculate number of elapsed milliseconds from current timestamp
     * @return Return elapsed milliseconds
     */
    uint64_t ElapsedMs()
    {
        std::unique_lock<std::mutex> mlock(_mutex);
        uint64_t tmp = _PreviousUs;
        mlock.unlock();
        _cond.notify_one();
        return ( millis() - (tmp/1000u) );
    }

    /**
     * @brief Calculate number of elapsed microseconds from current timestamp
     * @return Return elapsed microseconds
     */
    uint64_t ElapsedUs()
    {
        std::unique_lock<std::mutex> mlock(_mutex);
        uint64_t tmp = _PreviousUs;
        mlock.unlock();
        _cond.notify_one();
        return ( micros() - tmp );
    }

private:
    /** Timer's state */
    bool _IsRunning = false;
    /** Thread sync for read/write */
    std::mutex _mutex;
    std::condition_variable _cond;
    /** Remember when timer was stated */
    uint64_t _PreviousUs = 0;
};

Использование простое.Я просто создаю глобальную переменную, а затем обращаюсь к ней из нескольких разных потоков.

/* global variable */
Timer timer;
..............................
/* restart in some methods */
timer.Restart();
...............................
/* From some other threads */
if(timer.IsRunning())
{
    // retrieve time since Restsrt() then do something
    timer.ElapsedMs();

    // Restart eventually
    timer.Restart();
}

Она работает под Linux и пока работает нормально.Но кусок кода, который меня беспокоит, таков:

std::unique_lock<std::mutex> mlock(_mutex);
uint64_t tmp = _PreviousUs;
mlock.unlock();
_cond.notify_one();
return ( micros() - tmp );

Мне нужно создавать временную переменную каждый раз, когда я проверяю истекшее время ради «безопасности потока».Можно ли как-то улучшить мой код и одновременно обеспечить его многопоточность?

PS: я знаю, что могу использовать только функцию micros(), чтобы посчитать время максимально простым, но мои планыдля дальнейшего развития этого класса в будущем.

Позже правка: Мой вопрос не совсем в том, как мне получить временные метки.У меня вопрос, как я могу безопасно читать / писать _PreviousUs, учитывая, что один и тот же экземпляр класса Timer будет совместно использоваться несколькими потоками?

1 Ответ

0 голосов
/ 28 декабря 2018

Ваш класс выглядит неправильно.

Есть пример, как измерить время в std::chrono::duration_cast:

#include <iostream>
#include <chrono>
#include <ratio>
#include <thread>

void f()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    auto t1 = std::chrono::high_resolution_clock::now();
    f();
    auto t2 = std::chrono::high_resolution_clock::now();

    // floating-point duration: no duration_cast needed
    std::chrono::duration<double, std::milli> fp_ms = t2 - t1;

    // integral duration: requires duration_cast
    auto int_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);

    // converting integral duration to integral duration of shorter divisible time unit:
    // no duration_cast needed
    std::chrono::duration<long, std::micro> int_usec = int_ms;

    std::cout << "f() took " << fp_ms.count() << " ms, "
              << "or " << int_ms.count() << " whole milliseconds "
              << "(which is " << int_usec.count() << " whole microseconds)" << std::endl;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...