我正在尝试构建一个简单的线程安全时间计数器类。我设法编写的代码如下:
#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()
来尽可能简单地计算时间,但是我的计划是将来进一步开发此类。
后来编辑:我的问题不是我真的如何获得时间戳。我的问题是,鉴于Timer类的同一实例将在多个线程之间共享,我该如何读/写安全的_PreviousUs
?
答案 0 :(得分:1)
您的课程看起来不正确。
有一个示例如何在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;
}