Windows 7:过冲 C++ std::this_thread::sleep_for [英] Windows 7: overshoot C++ std::this_thread::sleep_for
问题描述
我们的代码是用 C++ 11 (VS2012/Win 7-64bit) 编写的.C++ 库提供了一个我们使用的 sleep_for
函数.我们观察到 C++ sleep_for
有时会出现很大的过冲.换句话说,我们请求睡眠 15 毫秒,但睡眠结果是例如100 毫秒.当系统负载很高时,我们会看到这一点.
我的第一反应是:当然,如果系统负载很大并且其他线程正在使用 CPU,那么睡眠需要更长的时间".然而,有趣"的是,如果我们将 sleep_for
替换为 Windows APISleep"调用,那么我们不会看到这种行为.我还看到 sleep_for
函数在水下调用了 Window API Sleep
方法.
sleep_for 的文档指出:
<块引用>该函数将调用线程阻塞至少Rel_time 指定的时间.此函数不会抛出任何异常.
因此从技术上讲,该功能正在运行.然而,我们没想到 C++ sleep_for
和常规的 Sleep(Ex)
函数之间存在差异.
有人可以解释这种行为吗?
如果使用 sleep_for 与 SleepEx,会执行相当多的额外代码.
例如在调试模式下调用 SleepEx(15) 会生成以下程序集 (Visual Studio 2015):
<代码>;9 : SleepEx(15, false);mov esi, esp推0按 15 ;0000000fH调用 DWORD PTR __imp__SleepEx@8cmp esi, esp调用 __RTC_CheckEsp
对比这段代码
const std::chrono::milliseconds duration(15);std::this_thread::sleep_for(duration);
生成以下内容:
<代码>;9 : std::this_thread::sleep_for(std::chrono::milliseconds(15));mov DWORD PTR $T1[ebp], 15 ;0000000fHlea eax, DWORD PTR $T1[ebp]推eaxlea ecx, DWORD PTR $T2[ebp]通话时长推eax调用 sleep_for添加 esp, 4
这会调用:
duration PROC ;std::chrono::duration<__int64,std::ratio<1,1000>>::duration<__int64,std::ratio<1,1000>><int,void>, COMDAT;_this$ = ecx;113 : {//从表示构造推ebpmov ebp, esp子 esp, 204 ;000000ccH推 ebx推esi推送编辑推ECXlea edi, DWORD PTR [ebp-204]mov ecx, 51 ;00000033Hmov eax, -858993460 ;cccccch代表停止流行音乐mov DWORD PTR _this$[ebp], ecx;112::_MyRep(static_cast<_Rep>(_Val))mov eax, DWORD PTR __Val$[ebp]mov eax, DWORD PTR [eax]cdqmov ecx, DWORD PTR _this$[ebp]mov DWORD PTR [ecx], eaxmov DWORD PTR [ecx+4], edx;114:}mov eax, DWORD PTR _this$[ebp]流行音乐流行音乐流行音乐mov esp, ebp流行音乐回复 4持续时间ENDP
并调用
sleep_for PROC ;std::this_thread::sleep_for<__int64,std::ratio<1,1000>>, COMDAT;151 : {//持续睡眠推ebpmov ebp, esp子 esp, 268 ;0000010cH推 ebx推esi推送编辑lea edi, DWORD PTR [ebp-268]mov ecx, 67 ;00000043Hmov eax, -858993460 ;cccccch代表停止mov eax, DWORD PTR ___security_cookie异或 eax, ebpmov DWORD PTR __$ArrayPad$[ebp], eax;第152话mov eax, DWORD PTR __Rel_time$[ebp]推eaxlea ecx, DWORD PTR $T1[ebp]推ECX调用 to_xtime添加 esp, 8mov edx, DWORD PTR [eax]mov DWORD PTR $T2[ebp], edxmov ecx, DWORD PTR [eax+4]mov DWORD PTR $T2[ebp+4], ecxmov edx, DWORD PTR [eax+8]mov DWORD PTR $T2[ebp+8], edxmov eax, DWORD PTR [eax+12]mov DWORD PTR $T2[ebp+12], eaxmov ecx, DWORD PTR $T2[ebp]mov DWORD PTR __Tgt$[ebp], ecxmov edx, DWORD PTR $T2[ebp+4]mov DWORD PTR __Tgt$[ebp+4], edxmov eax, DWORD PTR $T2[ebp+8]mov DWORD PTR __Tgt$[ebp+8], eaxmov ecx, DWORD PTR $T2[ebp+12]mov DWORD PTR __Tgt$[ebp+12], ecx;第153话lea eax, DWORD PTR __Tgt$[ebp]推eax调用 sleep_until添加 esp, 4;154:}推edxmov ecx, ebp推eaxlea edx, DWORD PTR $LN5@sleep_for调用@_RTC_CheckStackVars@8流行音乐流行音乐流行音乐流行音乐流行音乐mov ecx, DWORD PTR __$ArrayPad$[ebp]异或 ecx, ebp调用@__security_check_cookie@4添加 esp, 268 ;0000010cHcmp ebp, esp调用 __RTC_CheckEspmov esp, ebp流行音乐返回 0键盘3$LN5@sleep_for:DD 1DD $LN4@sleep_for$LN4@sleep_for:DD -24 ;ffffff8HDD 16 ;00000010HDD $LN3@sleep_for$LN3@sleep_for:数据库 95 ;0000005fH数据库 84 ;00000054H数据库 103 ;00000067H数据库 116 ;00000074H数据库 0sleep_for ENDP
发生了一些转换:
to_xtime PROC ;std::_To_xtime<__int64,std::ratio<1,1000>>, COMDAT;758 : {//将持续时间转换为 xtime推ebpmov ebp, esp子 ESP, 348 ;0000015cH推 ebx推esi推送编辑lea edi, DWORD PTR [ebp-348]mov ecx, 87 ;00000057Hmov eax, -858993460 ;cccccch代表停止mov eax, DWORD PTR ___security_cookie异或 eax, ebpmov DWORD PTR __$ArrayPad$[ebp], eax;第759话;760:如果(_Rel_time <= chrono::duration<_Rep,_Period>::zero())lea eax, DWORD PTR $T7[ebp]推eax通话时长_零;std::chrono::duration<__int64,std::ratio<1,1000>>::零添加esp,4推eaxmov ecx, DWORD PTR __Rel_time$[ebp]推ECX调用 chronos_operator ;std::chrono::operator<=<__int64,std::ratio<1,1000>,__int64,std::ratio<1,1000>>添加 esp, 8movzx edx, al测试edx,edxje SHORT $LN2@To_xtime;761 : {//负或零相对时间,返回零;762:_Xt.sec = 0;xorps xmm0, xmm0movlpd QWORD PTR __Xt$[ebp], xmm0;763:_Xt.nsec = 0;mov DWORD PTR __Xt$[ebp+8], 0;第764话;765:其他jmp $LN3@To_xtime$LN2@To_xtime:;766 : {//正相对时间,转换;767:计时::纳秒_T0 =;第768话lea eax, DWORD PTR $T5[ebp]推eaxlea ecx, DWORD PTR $T6[ebp]推ECX调用 system_clock_now ;std::chrono::system_clock::now添加 esp, 4mov ecx, eax调用 time_since_epoch ;std::chrono::time_point<std::chrono::system_clock,std::chrono::duration<__int64,std::ratio<1,10000000>>>::time_since_epoch推eaxlea ecx, DWORD PTR __T0$8[ebp]通话时长;std::chrono::duration<__int64,std::ratio<1,1000000000>>::duration<__int64,std::ratio<1,1000000000>><__int64,std::ratio<1,10000000>,void>;第769话mov eax, DWORD PTR __Rel_time$[ebp]推eaxlea ecx, DWORD PTR $T4[ebp]通话持续时间_比率;std::chrono::duration<__int64,std::ratio<1,1000000000>>::duration<__int64,std::ratio<1,1000000000>><__int64,std::ratio<1,1000>,void>lea ecx, DWORD PTR $T4[ebp]推ECXlea ecx, DWORD PTR __T0$8[ebp]通话持续时间_比率;std::chrono::duration<__int64,std::ratio<1,1000000000>>::运算符+=;770:_Xt.sec = chrono::duration_cast(_T0).count();lea eax, DWORD PTR __T0$8[ebp]推eaxlea ecx, DWORD PTR $T3[ebp]推ECX调用 duration_cast ;std::chrono::duration_cast>,__int64,std::ratio<1,1000000000>>添加 esp, 8mov ecx, eax通话时长_计数;std::chrono::duration<__int64,std::ratio<1,1>>::计数mov DWORD PTR __Xt$[ebp], eaxmov DWORD PTR __Xt$[ebp+4], edx;771:_T0-=计时::秒(_Xt.sec);lea eax, DWORD PTR __Xt$[ebp]推eaxlea ecx, DWORD PTR $T1[ebp]通话持续时间_比率;std::chrono::duration<__int64,std::ratio<1,1>>::duration<__int64,std::ratio<1,1>><__int64,void>推eaxlea ecx, DWORD PTR $T2[ebp]通话持续时间_比率;std::chrono::duration<__int64,std::ratio<1,1000000000>>::duration<__int64,std::ratio<1,1000000000>><__int64,std::ratio<1,1>,void>lea ecx, DWORD PTR $T2[ebp]推ECXlea ecx, DWORD PTR __T0$8[ebp]通话持续时间_比率;std::chrono::duration<__int64,std::ratio<1,1000000000>>::运算符-=;772:_Xt.nsec =(长)_T0.count();lea ecx, DWORD PTR __T0$8[ebp]通话持续时间_比率;std::chrono::duration<__int64,std::ratio<1,1000000000>>::计数mov DWORD PTR __Xt$[ebp+8], eax$LN3@To_xtime:;第773话;774:返回(_Xt);mov eax, DWORD PTR $T9[ebp]mov ecx, DWORD PTR __Xt$[ebp]mov DWORD PTR [eax], ecxmov edx, DWORD PTR __Xt$[ebp+4]mov DWORD PTR [eax+4], edxmov ecx, DWORD PTR __Xt$[ebp+8]mov DWORD PTR [eax+8], ecxmov edx, DWORD PTR __Xt$[ebp+12]mov DWORD PTR [eax+12], edxmov eax, DWORD PTR $T9[ebp];第775话推edxmov ecx, ebp推eaxlea edx, DWORD PTR $LN8@To_xtime调用@_RTC_CheckStackVars@8流行音乐流行音乐流行音乐流行音乐流行音乐mov ecx, DWORD PTR __$ArrayPad$[ebp]异或 ecx, ebp调用@__security_check_cookie@4添加 esp, 348 ;0000015cHcmp ebp, esp调用 __RTC_CheckEspmov esp, ebp流行音乐返回 0$LN8@To_xtime:DD 2DD $LN7@To_xtime$LN7@To_xtime:DD -24 ;ffffff8HDD 16 ;00000010HDD $LN5@To_xtimeDD -40 ;ffffffd8HDD 8DD $LN6@To_xtime$LN6@To_xtime:数据库 95 ;0000005fH数据库 84 ;00000054H数据库 48 ;00000030H数据库 0$LN5@To_xtime:数据库 95 ;0000005fH数据库 88 ;00000058H数据库 116 ;00000074H数据库 0to_xtime ENDP
最终调用了导入的函数,与 SleepEx 使用的函数相同.
sleep_until PROC ;std::this_thread::sleep_until,COMDAT;131 : {//睡眠直到_Abs_time推ebpmov ebp, esp子 esp, 192 ;000000c0H推 ebx推esi推送编辑lea edi, DWORD PTR [ebp-192]mov ecx, 48 ;00000030Hmov eax, -858993460 ;cccccch代表停止;132:_Thrd_sleep(_Abs_time);mov esi, espmov eax, DWORD PTR __Abs_time$[ebp]推eax调用 DWORD PTR __imp___Thrd_sleep添加 esp, 4cmp esi, esp调用 __RTC_CheckEsp;133:}流行音乐流行音乐流行音乐添加 esp, 192 ;000000c0Hcmp ebp, esp调用 __RTC_CheckEspmov esp, ebp流行音乐返回 0sleep_until ENDP
您还应该注意,根据 MSDN 文档,即使 SleepEx 也可能无法给出 100% 准确的结果https://msdn.microsoft.com/en-us/library/windows/desktop/ms686307(v=vs.85).aspx>
该函数导致线程放弃其剩余时间片,并在基于 dwMilliseconds 值的时间间隔内无法运行.系统时钟以恒定速率滴答作响".如果 dwMilliseconds 小于系统时钟的分辨率,线程可能会休眠少于指定的时间长度.如果 dwMilliseconds 大于 1 滴答但小于 2,则等待时间可以在一到两个滴答之间,依此类推.要提高睡眠间隔的准确性,请调用 timeGetDevCaps 函数来确定支持的最小计时器分辨率,并调用 timeBeginPeriod 函数将计时器分辨率设置为最小值.调用 timeBeginPeriod 时要小心,因为频繁调用会显着影响系统时钟、系统电源使用和调度程序.如果您调用 timeBeginPeriod,请在应用程序的早期调用一次,并确保在应用程序的最后调用 timeEndPeriod 函数.
Our code is written in C++ 11 (VS2012/Win 7-64bit). The C++ library provides a sleep_for
function that we use. We observed that the C++ sleep_for
sometimes shows a large overshoot. In other words we request to sleep for say 15 ms but the sleep turns out to be e.g. 100 ms. We see this when the load on the system is high.
My first reaction: "of course the sleeps "take longer" if there is a lot of load on the system and other threads are using the CPU".
However the "funny" thing is that if we replace the sleep_for
by a Windows API "Sleep" call then we do not see this behavior. I also saw that the sleep_for
function under water makes a call to the Window API Sleep
method.
The documentation for sleep_for states:
The function blocks the calling thread for at least the time that's specified by Rel_time. This function does not throw any exceptions.
So technically the function is working. However we did not expect to see a difference between C++ sleep_for
and the regular Sleep(Ex)
function.
Can somebody explain this behavior?
There is quite a bit of additional code executed if using sleep_for vs SleepEx.
For example calling SleepEx(15) generates the following assembly in debug mode (Visual Studio 2015):
; 9 : SleepEx(15, false);
mov esi, esp
push 0
push 15 ; 0000000fH
call DWORD PTR __imp__SleepEx@8
cmp esi, esp
call __RTC_CheckEsp
By contrast this code
const std::chrono::milliseconds duration(15);
std::this_thread::sleep_for(duration);
Generates the following:
; 9 : std::this_thread::sleep_for(std::chrono::milliseconds(15));
mov DWORD PTR $T1[ebp], 15 ; 0000000fH
lea eax, DWORD PTR $T1[ebp]
push eax
lea ecx, DWORD PTR $T2[ebp]
call duration
push eax
call sleep_for
add esp, 4
This calls into:
duration PROC ; std::chrono::duration<__int64,std::ratio<1,1000> >::duration<__int64,std::ratio<1,1000> ><int,void>, COMDAT
; _this$ = ecx
; 113 : { // construct from representation
push ebp
mov ebp, esp
sub esp, 204 ; 000000ccH
push ebx
push esi
push edi
push ecx
lea edi, DWORD PTR [ebp-204]
mov ecx, 51 ; 00000033H
mov eax, -858993460 ; ccccccccH
rep stosd
pop ecx
mov DWORD PTR _this$[ebp], ecx
; 112 : : _MyRep(static_cast<_Rep>(_Val))
mov eax, DWORD PTR __Val$[ebp]
mov eax, DWORD PTR [eax]
cdq
mov ecx, DWORD PTR _this$[ebp]
mov DWORD PTR [ecx], eax
mov DWORD PTR [ecx+4], edx
; 114 : }
mov eax, DWORD PTR _this$[ebp]
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 4
duration ENDP
And calls into
sleep_for PROC ; std::this_thread::sleep_for<__int64,std::ratio<1,1000> >, COMDAT
; 151 : { // sleep for duration
push ebp
mov ebp, esp
sub esp, 268 ; 0000010cH
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-268]
mov ecx, 67 ; 00000043H
mov eax, -858993460 ; ccccccccH
rep stosd
mov eax, DWORD PTR ___security_cookie
xor eax, ebp
mov DWORD PTR __$ArrayPad$[ebp], eax
; 152 : stdext::threads::xtime _Tgt = _To_xtime(_Rel_time);
mov eax, DWORD PTR __Rel_time$[ebp]
push eax
lea ecx, DWORD PTR $T1[ebp]
push ecx
call to_xtime
add esp, 8
mov edx, DWORD PTR [eax]
mov DWORD PTR $T2[ebp], edx
mov ecx, DWORD PTR [eax+4]
mov DWORD PTR $T2[ebp+4], ecx
mov edx, DWORD PTR [eax+8]
mov DWORD PTR $T2[ebp+8], edx
mov eax, DWORD PTR [eax+12]
mov DWORD PTR $T2[ebp+12], eax
mov ecx, DWORD PTR $T2[ebp]
mov DWORD PTR __Tgt$[ebp], ecx
mov edx, DWORD PTR $T2[ebp+4]
mov DWORD PTR __Tgt$[ebp+4], edx
mov eax, DWORD PTR $T2[ebp+8]
mov DWORD PTR __Tgt$[ebp+8], eax
mov ecx, DWORD PTR $T2[ebp+12]
mov DWORD PTR __Tgt$[ebp+12], ecx
; 153 : sleep_until(&_Tgt);
lea eax, DWORD PTR __Tgt$[ebp]
push eax
call sleep_until
add esp, 4
; 154 : }
push edx
mov ecx, ebp
push eax
lea edx, DWORD PTR $LN5@sleep_for
call @_RTC_CheckStackVars@8
pop eax
pop edx
pop edi
pop esi
pop ebx
mov ecx, DWORD PTR __$ArrayPad$[ebp]
xor ecx, ebp
call @__security_check_cookie@4
add esp, 268 ; 0000010cH
cmp ebp, esp
call __RTC_CheckEsp
mov esp, ebp
pop ebp
ret 0
npad 3
$LN5@sleep_for:
DD 1
DD $LN4@sleep_for
$LN4@sleep_for:
DD -24 ; ffffffe8H
DD 16 ; 00000010H
DD $LN3@sleep_for
$LN3@sleep_for:
DB 95 ; 0000005fH
DB 84 ; 00000054H
DB 103 ; 00000067H
DB 116 ; 00000074H
DB 0
sleep_for ENDP
Some conversion happens:
to_xtime PROC ; std::_To_xtime<__int64,std::ratio<1,1000> >, COMDAT
; 758 : { // convert duration to xtime
push ebp
mov ebp, esp
sub esp, 348 ; 0000015cH
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-348]
mov ecx, 87 ; 00000057H
mov eax, -858993460 ; ccccccccH
rep stosd
mov eax, DWORD PTR ___security_cookie
xor eax, ebp
mov DWORD PTR __$ArrayPad$[ebp], eax
; 759 : xtime _Xt;
; 760 : if (_Rel_time <= chrono::duration<_Rep, _Period>::zero())
lea eax, DWORD PTR $T7[ebp]
push eax
call duration_zero ; std::chrono::duration<__int64,std::ratio<1,1000> >::zero
add esp, 4
push eax
mov ecx, DWORD PTR __Rel_time$[ebp]
push ecx
call chronos_operator ; std::chrono::operator<=<__int64,std::ratio<1,1000>,__int64,std::ratio<1,1000> >
add esp, 8
movzx edx, al
test edx, edx
je SHORT $LN2@To_xtime
; 761 : { // negative or zero relative time, return zero
; 762 : _Xt.sec = 0;
xorps xmm0, xmm0
movlpd QWORD PTR __Xt$[ebp], xmm0
; 763 : _Xt.nsec = 0;
mov DWORD PTR __Xt$[ebp+8], 0
; 764 : }
; 765 : else
jmp $LN3@To_xtime
$LN2@To_xtime:
; 766 : { // positive relative time, convert
; 767 : chrono::nanoseconds _T0 =
; 768 : chrono::system_clock::now().time_since_epoch();
lea eax, DWORD PTR $T5[ebp]
push eax
lea ecx, DWORD PTR $T6[ebp]
push ecx
call system_clock_now ; std::chrono::system_clock::now
add esp, 4
mov ecx, eax
call time_since_ephoch ; std::chrono::time_point<std::chrono::system_clock,std::chrono::duration<__int64,std::ratio<1,10000000> > >::time_since_epoch
push eax
lea ecx, DWORD PTR __T0$8[ebp]
call duration ; std::chrono::duration<__int64,std::ratio<1,1000000000> >::duration<__int64,std::ratio<1,1000000000> ><__int64,std::ratio<1,10000000>,void>
; 769 : _T0 += _Rel_time;
mov eax, DWORD PTR __Rel_time$[ebp]
push eax
lea ecx, DWORD PTR $T4[ebp]
call duration_ratio ; std::chrono::duration<__int64,std::ratio<1,1000000000> >::duration<__int64,std::ratio<1,1000000000> ><__int64,std::ratio<1,1000>,void>
lea ecx, DWORD PTR $T4[ebp]
push ecx
lea ecx, DWORD PTR __T0$8[ebp]
call duration_ratio ; std::chrono::duration<__int64,std::ratio<1,1000000000> >::operator+=
; 770 : _Xt.sec = chrono::duration_cast<chrono::seconds>(_T0).count();
lea eax, DWORD PTR __T0$8[ebp]
push eax
lea ecx, DWORD PTR $T3[ebp]
push ecx
call duration_cast ; std::chrono::duration_cast<std::chrono::duration<__int64,std::ratio<1,1> >,__int64,std::ratio<1,1000000000> >
add esp, 8
mov ecx, eax
call duration_count ; std::chrono::duration<__int64,std::ratio<1,1> >::count
mov DWORD PTR __Xt$[ebp], eax
mov DWORD PTR __Xt$[ebp+4], edx
; 771 : _T0 -= chrono::seconds(_Xt.sec);
lea eax, DWORD PTR __Xt$[ebp]
push eax
lea ecx, DWORD PTR $T1[ebp]
call duration_ratio ; std::chrono::duration<__int64,std::ratio<1,1> >::duration<__int64,std::ratio<1,1> ><__int64,void>
push eax
lea ecx, DWORD PTR $T2[ebp]
call duration_ratio ; std::chrono::duration<__int64,std::ratio<1,1000000000> >::duration<__int64,std::ratio<1,1000000000> ><__int64,std::ratio<1,1>,void>
lea ecx, DWORD PTR $T2[ebp]
push ecx
lea ecx, DWORD PTR __T0$8[ebp]
call duration_ratio ; std::chrono::duration<__int64,std::ratio<1,1000000000> >::operator-=
; 772 : _Xt.nsec = (long)_T0.count();
lea ecx, DWORD PTR __T0$8[ebp]
call duration_ratio ; std::chrono::duration<__int64,std::ratio<1,1000000000> >::count
mov DWORD PTR __Xt$[ebp+8], eax
$LN3@To_xtime:
; 773 : }
; 774 : return (_Xt);
mov eax, DWORD PTR $T9[ebp]
mov ecx, DWORD PTR __Xt$[ebp]
mov DWORD PTR [eax], ecx
mov edx, DWORD PTR __Xt$[ebp+4]
mov DWORD PTR [eax+4], edx
mov ecx, DWORD PTR __Xt$[ebp+8]
mov DWORD PTR [eax+8], ecx
mov edx, DWORD PTR __Xt$[ebp+12]
mov DWORD PTR [eax+12], edx
mov eax, DWORD PTR $T9[ebp]
; 775 : }
push edx
mov ecx, ebp
push eax
lea edx, DWORD PTR $LN8@To_xtime
call @_RTC_CheckStackVars@8
pop eax
pop edx
pop edi
pop esi
pop ebx
mov ecx, DWORD PTR __$ArrayPad$[ebp]
xor ecx, ebp
call @__security_check_cookie@4
add esp, 348 ; 0000015cH
cmp ebp, esp
call __RTC_CheckEsp
mov esp, ebp
pop ebp
ret 0
$LN8@To_xtime:
DD 2
DD $LN7@To_xtime
$LN7@To_xtime:
DD -24 ; ffffffe8H
DD 16 ; 00000010H
DD $LN5@To_xtime
DD -40 ; ffffffd8H
DD 8
DD $LN6@To_xtime
$LN6@To_xtime:
DB 95 ; 0000005fH
DB 84 ; 00000054H
DB 48 ; 00000030H
DB 0
$LN5@To_xtime:
DB 95 ; 0000005fH
DB 88 ; 00000058H
DB 116 ; 00000074H
DB 0
to_xtime ENDP
Eventually the imported function gets called, the same one SleepEx has used.
sleep_until PROC ; std::this_thread::sleep_until, COMDAT
; 131 : { // sleep until _Abs_time
push ebp
mov ebp, esp
sub esp, 192 ; 000000c0H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-192]
mov ecx, 48 ; 00000030H
mov eax, -858993460 ; ccccccccH
rep stosd
; 132 : _Thrd_sleep(_Abs_time);
mov esi, esp
mov eax, DWORD PTR __Abs_time$[ebp]
push eax
call DWORD PTR __imp___Thrd_sleep
add esp, 4
cmp esi, esp
call __RTC_CheckEsp
; 133 : }
pop edi
pop esi
pop ebx
add esp, 192 ; 000000c0H
cmp ebp, esp
call __RTC_CheckEsp
mov esp, ebp
pop ebp
ret 0
sleep_until ENDP
You should also be aware even SleepEx may not give 100% exact results as per the MSDN documentation https://msdn.microsoft.com/en-us/library/windows/desktop/ms686307(v=vs.85).aspx
This function causes a thread to relinquish the remainder of its time slice and become unrunnable for an interval based on the value of dwMilliseconds. The system clock "ticks" at a constant rate. If dwMilliseconds is less than the resolution of the system clock, the thread may sleep for less than the specified length of time. If dwMilliseconds is greater than one tick but less than two, the wait can be anywhere between one and two ticks, and so on. To increase the accuracy of the sleep interval, call the timeGetDevCaps function to determine the supported minimum timer resolution and the timeBeginPeriod function to set the timer resolution to its minimum. Use caution when calling timeBeginPeriod, as frequent calls can significantly affect the system clock, system power usage, and the scheduler. If you call timeBeginPeriod, call it one time early in the application and be sure to call the timeEndPeriod function at the very end of the application.
这篇关于Windows 7:过冲 C++ std::this_thread::sleep_for的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!