Visual Studio 2017的CRT实现std::chrono::system_time使用哪个钟?

5

Chrono头文件中的注释只是说

// wraps GetSystemTimePreciseAsFileTime/GetSystemTimeAsFileTime

但是它实际使用的是什么精度(即我可以期望什么精度)?该实现调用_Xtime_get_ticks,但该函数是不透明的。


1
“我能期望什么样的精度?”你可以通过 system_clock::period 向时钟询问其提供的精度。 - Nicol Bolas
1
不是不透明的...可以在C:\Program Files (x86)\Windows Kits...\Source中查看源代码。 - rustyx
1
GetSystemTimePreciseAsFileTime 的文档说明可以期望小于1微秒的精度。 - Adrian McCarthy
3个回答

4
CRT在可用时调用GetSystemTimePreciseAsFileTime,否则调用GetSystemTimeAsFileTimeGetSystemTimePreciseAsFileTime提供了最高精度(<1us)

在运行时的初始化过程中,会调用名为initialize_pointers的函数,该函数基本上执行以下操作(反编译并简化):

HMODULE hModule = GetModuleHandleW(L"kernel32.dll");

__encodedKERNEL32Functions[0] = (void *)GetProcAddress(hModule, "FlsAlloc");
__encodedKERNEL32Functions[1] = (void *)GetProcAddress(hModule, "FlsFree");
__encodedKERNEL32Functions[2] = (void *)GetProcAddress(hModule, "FlsGetValue");
__encodedKERNEL32Functions[3] = (void *)GetProcAddress(hModule, "FlsSetValue");

...


__encodedKERNEL32Functions[24] = (void *)GetProcAddress(hModule, "GetSystemTimePreciseAsFileTime");

...

在Windows 8或更新版本的系统上,__encodedKERNEL32Functions[24]将不为零。 这归结于以下原因:
std::chrono::system_clock::now()
-> _Xtime_get_ticks
   -> __crtGetSystemTimePreciseAsFileTime(FILETIME *)

void __crtGetSystemTimePreciseAsFileTime(FILETIME *lpSystemTimeAsFileTime)
{
    void (*f)(FILETIME *) = (void (*)(FILETIME *))__encodedKERNEL32Functions[24];
    if (f)                         // if GetSystemTimePreciseAsFileTime exists
        f(lpSystemTimeAsFileTime); // call it
    else
        GetSystemTimeAsFileTime(lpSystemTimeAsFileTime);
}

至少在 msvcp140.dllmsvcp140d.dll 的版本14.16.27024.1 中,它的实现方式是这样的(大约)。

所有这些当然都没有文档记录,并且可能会发生改变。

如果您需要使用 GetSystemTimePreciseAsFileTime,则应该编写自己的时钟,而不是依赖于实现细节。


2

让我们在这里做一些调研。首先,在Visual C++运行时库中查找"_Xtime_get_ticks":

C:\Windows\SysWOW64>dumpbin /exports msvcp140.dll|findstr /I "Xtime"
       1483  5CA 0000B5D0 _Xtime_diff_to_millis
       1484  5CB 0000B610 _Xtime_diff_to_millis2
       1485  5CC 0000B650 _Xtime_get_ticks
       1515  5EA 0000B730 xtime_get

然后,我使用dumpbin /disasm msvcp140.dll命令,同时在同一目录下放置msvcp140.i386.pdb文件:


__Xtime_get_ticks:
  1000B650: ... boilerplate ...
  1000B659: E8 22 50 02 00     call        ___crtGetSystemTimePreciseAsFileTime

在这个反汇编函数中,没有任何 GetSystemTimeAsFileTimecall 指令,因此很明显 GetSystemTimePreciseAsFileTime 是底层实现中唯一被调用的函数。


如果msvcrt源代码可用,为什么要跳过所有这些步骤呢? - SergeyA
@SergeyA 这是我习惯用于这种事情的方法。 - Govind Parmar

2
long long _Xtime_get_ticks()
{   /* get system time in 100-nanosecond intervals since the epoch */
FILETIME ft;
__crtGetSystemTimePreciseAsFileTime(&ft);
return ((((long long)ft.dwHighDateTime) << 32)
    + (long long)ft.dwLowDateTime - EPOCH);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接