Windows7:超调C++;std::此线程::睡眠 我们的代码是用C++ 11编写的(VS201/Win 764位)。C++库为我们使用的函数提供了睡眠。我们观察到的C++ +>代码>睡眠有时表现出较大的过冲。换句话说,我们要求睡眠15毫秒,但睡眠时间为100毫秒。当系统负载较高时,我们会看到这种情况
我的第一个反应是:“当然,如果系统上有很多负载,而其他线程正在使用CPU,那么睡眠时间会更长”。 然而,“有趣的”是,如果我们用Windows API“sleep”调用替换的Windows7:超调C++;std::此线程::睡眠 我们的代码是用C++ 11编写的(VS201/Win 764位)。C++库为我们使用的函数提供了睡眠。我们观察到的C++ +>代码>睡眠有时表现出较大的过冲。换句话说,我们要求睡眠15毫秒,但睡眠时间为100毫秒。当系统负载较高时,我们会看到这种情况,c++,windows,winapi,sleep,C++,Windows,Winapi,Sleep,我的第一个反应是:“当然,如果系统上有很多负载,而其他线程正在使用CPU,那么睡眠时间会更长”。 然而,“有趣的”是,如果我们用Windows API“sleep”调用替换的sleep\u,那么我们就看不到这种行为。我还看到水下sleep\u for函数调用windowapisleep方法 各国的文件: 函数至少在Rel_time指定的时间内阻止调用线程。此函数不会引发任何异常 因此,从技术上讲,该功能正在发挥作用。但是,我们并没有看到C++ 睡眠>对于和常规睡眠(EX)< /C>函数。 有人能
sleep\u,那么我们就看不到这种行为。我还看到水下sleep\u for
函数调用windowapisleep
方法
各国的文件:
函数至少在Rel_time指定的时间内阻止调用线程。此函数不会引发任何异常
因此,从技术上讲,该功能正在发挥作用。但是,我们并没有看到C++ <代码>睡眠>对于和常规<代码>睡眠(EX)< /C>函数。
有人能解释一下这种行为吗?如果对vs SleepEx使用sleep_,会执行很多额外的代码
例如,调用SleepEx(15)在调试模式下生成以下程序集(Visual Studio 2015):
相比之下,这个代码
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 ; 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
这需要:
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
您还应注意,根据MSDN文档,即使SleepEx也可能无法给出100%的准确结果
此函数使线程放弃剩余的时间片,并在基于DWM毫秒值的间隔内变得不可命名。系统时钟以恒定速率“滴答”作响。如果dwms小于系统时钟的分辨率,则线程的睡眠时间可能小于指定的时间长度。如果DWM大于一个刻度但小于两个,则等待时间可以在一到两个刻度之间,依此类推。要提高睡眠间隔的准确性,请调用timeGetDevCaps函数确定支持的最小计时器分辨率,并调用timeBeginPeriod函数将计时器分辨率设置为其最小值。调用timeBeginPeriod时请小心,因为频繁的调用会显著影响系统时钟、系统电源使用和计划程序。如果调用timeBeginPeriod,请在应用程序的早期调用它一次,并确保在应用程序的最后调用timeEndPeriod函数。在绝大多数操作系统(包括Windows、Linux和BSD)上,对于过度睡眠和睡眠不足,睡眠通常都不可靠。半个C++ C++线程库的坏措辞(真的,花费了这么长时间,线程已经被研究了几十年了,你不能想出更好的东西)。需要——看到发布的引用——一个兼容的实现首先睡觉,然后调用一个时间函数来检查确实请求的最小值已经通过了,可能还会再睡觉。这真是太没用了,太愚蠢了……一句话,
的sleep\u和sleep
(Win32)根本不是一回事。@Damon,你所描述的是睡眠直到所需要的,而不是睡眠的sleep\u,并且只对可以调整的非单调时钟是必需的。为
实现sleep\u不需要调用时间函数。例如,如果它是使用nanosleep
实现的,那么该函数将告诉您它是否在请求的时间内睡眠(或者被信号中断并提前返回)。@Damon:我刚刚检查了Visual Studio 2015的sleep\u的实现。它只计算过期时间,并将调用转发到sleep\u,直到
sleep\u直到
然后调用sleep
,这可能是一个循环,以防止提前到期。总之,sleep\u for
和sleep
几乎是一样的,只是sleep\u for
不会提前过期。@IInspectable:不,正如您所说,sleep\u until
运行循环,而sleep\u for
调用前者。这正是我要说的。睡眠两次可能会导致这种“花很长时间”的现象。每次睡眠时,请求的时间都会四舍五入到调度程序粒度(在Vista之前和Vista之后的窗口中也是不同的),并且线程在该时间结束之前(通常)不会准备就绪。可通过以下事实进行验证:for(int i=0;i<1000;++i)Sleep(1)代码>比睡眠(1000)
需要更长的时间。事实上,你是否早点回来根本不重要。。。
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
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
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
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