Windows 7:过冲 C++ std::this_thread::sleep_for [英] Windows 7: overshoot C++ std::this_thread::sleep_for

查看:33
本文介绍了Windows 7:过冲 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆