如何在 c++ 中以毫秒为单位获得系统启动时间?

Posted

技术标签:

【中文标题】如何在 c++ 中以毫秒为单位获得系统启动时间?【英文标题】:How do I get system up time in milliseconds in c++? 【发布时间】:2015-07-17 16:39:07 【问题描述】:

如何获得系统启动后的系统启动时间?我发现的只是时代以来的时间,没有别的。

例如,像 ctime 库中的 time() 之类的东西,但它只给我一个自纪元以来的秒值。我想要类似 time() 的东西,但从系统启动开始。

【问题讨论】:

取决于系统。 我的意思是从计算机启动开始。我想获取系统计时器值。有没有跨平台的方法? @dandan:供未来用户参考,此线程可能对所有系统都有答案。 【参考方案1】:

它依赖于操作系统,并且已经在 *** 上为多个系统提供了答案。

#include<chrono> // for all examples :)

Windows ...

使用GetTickCount64()(分辨率通常为10-16毫秒)

#include <windows>
// ...
auto uptime = std::chrono::milliseconds(GetTickCount64());

Linux ...

... 使用/proc/uptime

#include <fstream>
// ...
std::chrono::milliseconds uptime(0u);
double uptime_seconds;
if (std::ifstream("/proc/uptime", std::ios::in) >> uptime_seconds)

  uptime = std::chrono::milliseconds(
    static_cast<unsigned long long>(uptime_seconds*1000.0)
  );

...使用sysinfo(分辨率1秒)

#include <sys/sysinfo.h>
// ...
std::chrono::milliseconds uptime(0u);
struct sysinfo x;
if (sysinfo(&x) == 0)

  uptime = std::chrono::milliseconds(
    static_cast<unsigned long long>(x.uptime)*1000ULL
  );

OS X ...

... 使用sysctl

#include <time.h>
#include <errno.h>
#include <sys/sysctl.h>
// ...
std::chrono::milliseconds uptime(0u);
struct timeval ts;
std::size_t len = sizeof(ts);
int mib[2] =  CTL_KERN, KERN_BOOTTIME ;
if (sysctl(mib, 2, &ts, &len, NULL, 0) == 0)

  uptime = std::chrono::milliseconds(
    static_cast<unsigned long long>(ts.tv_sec)*1000ULL + 
    static_cast<unsigned long long>(ts.tv_usec)/1000ULL
  );

类 BSD 系统(或分别支持 CLOCK_UPTIMECLOCK_UPTIME_PRECISE 的系统)...

...使用clock_gettime(分辨率见clock_getres

#include <time.h>
// ... 
std::chrono::milliseconds uptime(0u);
struct timespec ts;
if (clock_gettime(CLOCK_UPTIME_PRECISE, &ts) == 0)

  uptime = std::chrono::milliseconds(
    static_cast<unsigned long long>(ts.tv_sec)*1000ULL + 
    static_cast<unsigned long long>(ts.tv_nsec)/1000000ULL
   );

【讨论】:

另外,有没有跨平台的获取方式? 它必须是static_cast&lt;unsigned long long&gt;(uptime_seconds*1000),因为uptime_seconds 包括毫秒,例如8084.13 * 1000 = 8084130 mS 而不是8084 * 1000 = 8084000 mS【参考方案2】:

+1 接受的答案。不错的调查。但 OS X 的答案不正确,我想在这里显示更正。

在 OS X 上输入 CTL_KERN, KERN_BOOTTIME sysctl 函数返回系统启动后的 Unix Time,而不是自启动以来的时间。在这个系统(以及所有其他系统)上,std::chrono::system_clock 也测量Unix Time。因此,只需减去这两个 time_points 即可获得自启动以来的时间。以下是您如何修改已接受答案的 OS X 解决方案来执行此操作:

std::chrono::milliseconds
uptime()

    using namespace std::chrono;
    timeval ts;
    auto ts_len = sizeof(ts);
    int mib[2] =  CTL_KERN, KERN_BOOTTIME ;
    auto constexpr mib_len = sizeof(mib)/sizeof(mib[0]);
    if (sysctl(mib, mib_len, &ts, &ts_len, nullptr, 0) == 0)
    
        system_clock::time_point bootsecondsts.tv_sec + microsecondsts.tv_usec;
        return duration_cast<milliseconds>(system_clock::now() - boot);
    
    return 0ms;

注意事项:

最好chrono 为您进行单位转换。如果您的代码中包含1000(例如,将秒转换为毫秒),请将其重写为让chrono 进行转换。 如果它们编译,您可以依赖隐式计时持续时间单位转换是正确的。如果它们无法编译,则意味着您要求截断,您可以使用 duration_cast 明确要求截断。 如果可以使代码更具可读性,可以在函数中本地使用 using 指令

【讨论】:

'system_clock' 不是单调的,因此,减去now-boot 可能会导致错误甚至负值? 是的,但要做到这一点需要有人积极尝试阻止系统。在正常情况下,计算机对 Unix 时间的跟踪会通过少量时间进行调整,以以廉价石英钟的精度跟踪正确的时间。夏令时和更改时区都不会影响system_clock 返回的值。学究起来,now-boot 在正常情况下可能会有点错误,因为 macOS 不包含完美的时钟。 @Howard Hinnant:需要有人纠正系统时间才能做到这一点。或者有人重新配置 NTP 源。或者一个时钟电池烧坏的系统(它们持续大约 10 年),它在引导期间使用 NTP 更正系统时间。无需积极尝试阻挠所需的系统。【参考方案3】:

有一个boost example关于如何自定义日志消息。

作者在其中实现了一个简单的函数unsigned int get_uptime() 来获取不同平台的系统正常运行时间,包括 Windows、OSx、Linux 以及 BSD。

【讨论】:

对 Windows 使用 GetTickCount,对 Linux 使用 sysinfoclock_gettime,对 OS X 使用 sysctl

以上是关于如何在 c++ 中以毫秒为单位获得系统启动时间?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Mysql 中以 unix 毫秒为单位存储日期?

如何在 Ruby 中以毫秒为单位计时?

c++代码执行定时器返回0,需要以毫秒为单位输出

为啥 setDate() 在 nodejs 中以毫秒为单位给出最终日期? [复制]

想要在存储过程中以毫秒为单位获取两个时间戳的差异

MySql 中以毫秒为单位的 AVG 时间