Я пытаюсь создать простой потокобезопасный счетчик времени.Код, который мне удалось написать, выглядит следующим образом:
#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 будет совместно использоваться несколькими потоками?