在程序中,我們經常需要獲取當前的時間戳到毫秒甚至微妙級,但是頻繁的調用API會對程序的性能有些許影響,並且要還要考慮不同平臺的影響。參考大佬https://www.jianshu.com/p/c9b775d831fb的實現,積累下關於頻繁獲取時間戳的知識。
實現的思路是:
- 設置兩個原子變量,分別記錄當前的毫秒和微妙的時間戳。
- 啓動一個時間的線程,每隔一個時間間隔,獲取當前最新的時間戳,並更新兩個原子變量。注意,線程爲分離屬性。
- 當獲取最新時間時,只要將對應的原子變量值返回就可以了。
- 在linux平臺下使用性能最好的gettimeofday(),在windows平臺下,使用std::chrono.
#include <atomic>
#include <chrono>
#include <thread>
#include <functional>
using namespace std;
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif //_WIN32
//該類藉助RAII思想,使傳入的task對象可以成對進行,而不考慮釋放的問題
class onceToken {
public:
typedef function<void(void)> task;
onceToken(const task &onConstructed, const task &onDestructed = nullptr) {
if (onConstructed) {
onConstructed();
}
_onDestructed = onDestructed;
}
onceToken(const task &onConstructed, task &&onDestructed) {
if (onConstructed) {
onConstructed();
}
_onDestructed = std::move(onDestructed);
}
~onceToken() {
if (_onDestructed) {
_onDestructed();
}
}
private:
onceToken();
onceToken(const onceToken &);
onceToken(onceToken &&);
onceToken &operator =(const onceToken &)=delete;
onceToken &operator =(onceToken &&) = delete;
task _onDestructed;
};
static inline uint64_t getCurrentMicrosecondOrigin() {
#if !defined(_WIN32)
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000LL + tv.tv_usec;
#else
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
#endif
}
static atomic<uint64_t> s_currentMicrosecond(getCurrentMicrosecondOrigin());
static atomic<uint64_t> s_currentMillisecond(getCurrentMicrosecondOrigin() / 1000);
static inline bool initMillisecondThread() {
static std::thread s_thread([]() {
uint64_t now;
while (true) {
now = getCurrentMicrosecondOrigin();
s_currentMicrosecond.store(now, memory_order_release);
s_currentMillisecond.store(now / 1000, memory_order_release);
#if !defined(_WIN32)
//休眠0.5 ms
usleep(500);
#else
Sleep(1);
#endif
}
});
static onceToken s_token([]() {
s_thread.detach();
});
return true;
}
uint64_t getCurrentMillisecond() {
static bool flag = initMillisecondThread();
return s_currentMillisecond.load(memory_order_acquire);
}
uint64_t getCurrentMicrosecond() {
static bool flag = initMillisecondThread();
return s_currentMicrosecond.load(memory_order_acquire);
}
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
while (1)
{
cout << "-----" << getCurrentMillisecond() << endl;
cout << "*****" << getCurrentMicrosecond() << endl;
Sleep(1000);
}
getchar();
return 0;
}