Winapi 使用timeSetEvent解析WaitForSingleObject&;当时间到时
我正在使用Win32多媒体计时器在发送大量UDP数据包之间设置延迟,但我发现由此产生的延迟远远超过了应有的时间。即使在使用Windows Miltimedia计时器并提高计时器分辨率时,~40ms的延迟有时也接近1000ms。下面是我使用的代码的简化版本:Winapi 使用timeSetEvent解析WaitForSingleObject&;当时间到时,winapi,waitforsingleobject,Winapi,Waitforsingleobject,我正在使用Win32多媒体计时器在发送大量UDP数据包之间设置延迟,但我发现由此产生的延迟远远超过了应有的时间。即使在使用Windows Miltimedia计时器并提高计时器分辨率时,~40ms的延迟有时也接近1000ms。下面是我使用的代码的简化版本: if( timeGetDevCaps(&tc,sizeof(TIMECAPS)) == TIMERR_NOERROR) { timeRes = min( max(tc.wPeriodMin,1), tc.wPerio
if( timeGetDevCaps(&tc,sizeof(TIMECAPS)) == TIMERR_NOERROR)
{
timeRes = min( max(tc.wPeriodMin,1), tc.wPeriodMax);
timeBeginPeriod(timeRes);
printf("Timer Res: %u\n", timeRes);
}
/* ... */
while( ptrHead )
{
NALU_t *ptrLink = ptrHead;
unsigned long tsNALU = ptrLink->timestamp - tsFirst;
printf("Timestamp: %umsec\n", ptrLink->timestamp / 90 );
int idxPort;
for(idxPort=0;idxPort<12;idxPort++)
{
ip4Addr.sin_port = htons( 60000 + idxPort );
struct sockaddr *saAddr = (struct sockaddr*)&ip4Addr;
sendto(fdSocket,(char*)ptrLink->ptrData,ptrLink->lenData,
0,saAddr,lenAddr);
}
if( 1 )
{
unsigned long millis = (tsNALU - tsPrev) / 90;
valTime.QuadPart = 10000;
valTime.QuadPart *= millis;
valTime.QuadPart *= -1;
if(SetWaitableTimer(hdlTimer,&valTime,0,NULL,NULL,TIME_ONESHOT))
WaitForSingleObject(hdlTimer,INFINITE);
}
tsPrev = tsNALU;
ptrHead = ptrLink->next;
free( ptrLink );
}
if(timeGetDevCaps(&tc,sizeof(TIMECAPS))==TIMERR\u NOERROR)
{
timeRes=min(max(tc.wPeriodMin,1),tc.wPeriodMax);
timeBeginPeriod(timeRes);
printf(“计时器分辨率:%u\n”,计时器分辨率);
}
/* ... */
while(ptrHead)
{
NALU_t*ptrLink=ptrHead;
无符号长tsNALU=ptrLink->timestamp-tsFirst;
printf(“时间戳:%umsec\n”,ptrLink->Timestamp/90);
int-idxPort;
对于(idxPort=0;idxPortptrData,ptrLink->lenData,
0,saAddr,lenAddr);
}
如果(1)
{
无符号长毫秒=(tsNALU-tsPrev)/90;
valTime.QuadPart=10000;
valTime.QuadPart*=毫秒;
valTime.QuadPart*=-1;
if(SetWaitableTimer(hdlTimer和valTime,0,NULL,NULL,TIME_ONESHOT))
WaitForSingleObject(hdlTimer,无限);
}
tsPrev=tsNALU;
ptrHead=ptrLink->next;
免费(ptrLink);
}
我怀疑问题在于Windows7不再保证事件发出信号时计时器的分辨率,而不是回调,但我讨厌使用后者。有人知道为什么单线程测试用例中的高分辨率计时器如此不准确吗?如果计时非常关键,最好在繁忙的循环中运行(如果愿意,可以使用Sleep(0)放弃每次迭代的时间片),使用QueryPerformanceCounter()API测量经过的时间。来自后续实验,我最好的猜测是,Windows在CPU核之间移动线程(可能是出于负载平衡的原因——这是在四核i7上)会破坏定时功能。我使用
SetThreadAffinityMask()
将计时关键线程锁定到一个CPU(将非计时线程锁定到所有其他内核),这样就解决了问题。计时器的分辨率永远无法保证。他们仍然依赖于流程/系统正在做的任何其他事情。当没有加载时,它们应该足够接近。我知道将“保证”和“窗口”放在同一句话中是对术语的滥用,但WinMM的准确性不应该如此糟糕:)我本来打算避免繁忙的循环,但函数的MSDN页面上有一条关于使用SetThreadAffinityMask()的注释,这使我走上了正确的道路。