threads and their time slots. [modified]
-
Good morning :), just a brief question. I got a multi-threaded program. Now is it possible to ensure that a certain thread at a certain point won´t lose its 'working permission'. Hm, don´t know if I expressed that correctly. I have a thread going into a function where it has to wait for a previously defined time, then go on. The thing is, it waits and waits and at some point its time slot is taken away. When it is given the next slot, though, the time it has waited for has 'long' passed. And thus it´s always too late. The code in question is:
int RTPEngine::SendRTPPacket( BYTE* data, int size )
{
if( data && size > 0 && m_pHeader )
{
m_pLogger->Out(Logger::DEBUG, "RTPEngine: Sending data package with size %d (excluding header).\n", size);BYTE\* packet = new BYTE\[size+12\]; BYTE\* headerBytes = m\_pHeader->GetInc(); for( int i = 0; i < 12; i++ ) { packet\[i\] = headerBytes\[i\]; } for( int i = 0; i < size; i++ ) { packet\[i+12\] = data\[i\]; } double now = 0.0; // milliseconds if( m\_dPacketSendTime != 0.0 ) { now = ((double) clock() / CLK\_TCK) \* 1000; // milliseconds int tmp = 0; //m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Time now = %f.\\n", now ); while( now <= m\_dPacketSendTime ) { if( tmp >= 20 ) { m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Time now = %f, send time = %f.\\n", now, m\_dPacketSendTime ); tmp = 0; } tmp++; now = ((double) clock() / CLK\_TCK) \* 1000; } } now = ((double) clock() / CLK\_TCK) \* 1000; int rc=sendto(m\_oUDPSocket,(char\*)packet,size+12,0,(SOCKADDR\*)&m\_oUDPAddress,sizeof(SOCKADDR\_IN)); m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Packet sent at = %f.\\n", now ); m\_dPacketSendTime = ((double) clock() / CLK\_TCK) \* 1000; // milliseconds m\_dPacketSendTime += (m\_dPacketLengthMillis\*(1.0 - m\_dRTPOverlap)); m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Next send time = %f.\\n", m\_dPacketSendTime ); return size; } else return 0;
}
And one more thing is, on my Vista machine it works fine. The logger prints this: RTPEngine: Next send time = 53637.795918. RTPEngine: Sending data package with size 480 (excluding header). RTPEngine: Time now = 53628.000000, send time = 53637.795918. . . . RTPEngine: Time now = 53636.000000, send time = 53637.795918. RTPEngine: Time now = 53636.000000, send time = 53637.795918. RTPEngine: Time now = 53637.000000, send time = 53637.795918. RTPEngine: Time now = 536
It could be the use of the clock() function; on your XP machine it seems to have a much coarser granularity as the time isn't changing at all in the loop. I always use GetTickCount() for millisecond timing - you can work with integers and don't have to bother doing any division. It's never going to be accurate to a millisecond though; I tried a similar loop on my system and only got a different value about every 15 ms even though I was continually calling the function.
-
I put together a wee program demonstrating waitable timer usage:
#include "stdafx.h"
#include <iostream>
#include <Windows.h>void ReportTime(const char* message, LONGLONG const& when)
{
std::cout << message << double(when)/10000.0 << std::endl;
}VOID CALLBACK DoSendHere(__in_opt LPVOID lpArgToCompletionRoutine,
__in DWORD dwTimerLowValue,
__in DWORD dwTimerHighValue)
{
LARGE_INTEGER const& ftSleepStart = *(LARGE_INTEGER*)lpArgToCompletionRoutine;
LARGE_INTEGER liTimer;
liTimer.LowPart = dwTimerLowValue;
liTimer.HighPart = dwTimerHighValue;
ReportTime("DoSendHere::Timer slept for ", liTimer.QuadPart-ftSleepStart.QuadPart);
delete lpArgToCompletionRoutine;
}int SendLoop()
{
LARGE_INTEGER ftStart;
GetSystemTimeAsFileTime((FILETIME*)&ftStart);
HANDLE hTimer = 0;
hTimer = ::CreateWaitableTimer(0, TRUE, L"WaitableTimer");LARGE_INTEGER ftNow;
LARGE_INTEGER ftWaitTill;
GetSystemTimeAsFileTime((FILETIME*)&ftNow);
while(1)
{
ReportTime("SendLoop::Now = ", ftNow.QuadPart-ftStart.QuadPart);ftWaitTill.QuadPart = ftNow.QuadPart + 5000000I64; SetWaitableTimer(hTimer, &ftWaitTill, 0, &DoSendHere, new LARGE\_INTEGER(ftNow), FALSE); ftNow = ftWaitTill; ::SleepEx(INFINITE, TRUE);
}
}int _tmain(int argc, _TCHAR* argv[])
{
SendLoop();
return 0;
}This is intended to set a timer for 500ms in the future and sleep until the timer's triggered, at which point a) the completion routine is called, and b) the SleepEx call exits. I get this output (on Windows XP SP 3):
SendLoop::Now = 0
DoSendHere::Timer slept for 499.978
SendLoop::Now = 500
DoSendHere::Timer slept for 499.955
SendLoop::Now = 1000
DoSendHere::Timer slept for 499.933
SendLoop::Now = 1500
DoSendHere::Timer slept for 499.91
SendLoop::Now = 2000
DoSendHere::Timer slept for 499.888
SendLoop::Now = 2500
DoSendHere::Timer slept for 499.866
SendLoop::Now = 3000
DoSendHere::Timer slept for 499.843
SendLoop::Now = 3500
DoSendHere::Timer slept for 499.821
SendLoop::Now = 4000
DoSendHere::Timer slept for 499.798
SendLoop::Now = 4500
DoSendHere::Timer slept for 499.776
SendLoop::Now = 5000
DoSendHere::Timer slept for 499.754
SendLoop::Now = 5500
DoSendHere::Timer slept for 499.731
SendLoop::Now = 6000
DoSendHere::Timer slept for 499.709
SendLoop::Now = 6500
DoSendHere::Timer slept forThanks for that. I highly appreciate you getting into this so much. I all but copied your code and it works on my machine. But as soon as I put it on our server machine, the ol´ troublemakers show up again. I set a sleep time of appx. 10ms and usually the thing sleeps the day away ... well, 15 ms :). The output in my case is
RTPEngine: Next send time = 12891106961478.547000.
RTPEngine: Sending data package with size 480 (excluding header).
RTPEngine: Time now = 12891106961468.750000.
DoSendHere::Timer slept for 15.625000
RTPEngine: Packet sent at = 12891106961484.375000.
RTPEngine: Next send time = 12891106961494.172000.
RTPEngine: Sending data package with size 480 (excluding header).
RTPEngine: Time now = 12891106961484.375000.
DoSendHere::Timer slept for 0.000000
RTPEngine: Packet sent at = 12891106961484.375000.
RTPEngine: Next send time = 12891106961494.172000.
RTPEngine: Sending data package with size 480 (excluding header).
RTPEngine: Time now = 12891106961484.375000.
DoSendHere::Timer slept for 15.625000
RTPEngine: Packet sent at = 12891106961500.000000.
RTPEngine: Next send time = 12891106961509.797000.
JobManager: Job 0_0 processed packet with size 2048. Packets available: 67
RTPEngine: Preparing to send data bundle with size of 1520 bytes.
RTPEngine: Adding leftover (352 bytes).
RTPEngine: Sending data package with size 480 (excluding header).
RTPEngine: Time now = 12891106961500.000000.
DoSendHere::Timer slept for 15.625000
RTPEngine: Packet sent at = 12891106961515.625000.
RTPEngine: Next send time = 12891106961525.422000.
RTPEngine: Sending data package with size 480 (excluding header).
RTPEngine: Time now = 12891106961515.625000.
DoSendHere::Timer slept for 15.625000
RTPEngine: Packet sent at = 12891106961531.250000.What bugs me even more than that (as seen in the output) is that the Timer sometimes sleeps for 0 ms even though it should wait. Looking into it ... might be something with threads and time-slices, after all. Souldrift
-
It could be the use of the clock() function; on your XP machine it seems to have a much coarser granularity as the time isn't changing at all in the loop. I always use GetTickCount() for millisecond timing - you can work with integers and don't have to bother doing any division. It's never going to be accurate to a millisecond though; I tried a similar loop on my system and only got a different value about every 15 ms even though I was continually calling the function.
-
Good morning :), just a brief question. I got a multi-threaded program. Now is it possible to ensure that a certain thread at a certain point won´t lose its 'working permission'. Hm, don´t know if I expressed that correctly. I have a thread going into a function where it has to wait for a previously defined time, then go on. The thing is, it waits and waits and at some point its time slot is taken away. When it is given the next slot, though, the time it has waited for has 'long' passed. And thus it´s always too late. The code in question is:
int RTPEngine::SendRTPPacket( BYTE* data, int size )
{
if( data && size > 0 && m_pHeader )
{
m_pLogger->Out(Logger::DEBUG, "RTPEngine: Sending data package with size %d (excluding header).\n", size);BYTE\* packet = new BYTE\[size+12\]; BYTE\* headerBytes = m\_pHeader->GetInc(); for( int i = 0; i < 12; i++ ) { packet\[i\] = headerBytes\[i\]; } for( int i = 0; i < size; i++ ) { packet\[i+12\] = data\[i\]; } double now = 0.0; // milliseconds if( m\_dPacketSendTime != 0.0 ) { now = ((double) clock() / CLK\_TCK) \* 1000; // milliseconds int tmp = 0; //m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Time now = %f.\\n", now ); while( now <= m\_dPacketSendTime ) { if( tmp >= 20 ) { m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Time now = %f, send time = %f.\\n", now, m\_dPacketSendTime ); tmp = 0; } tmp++; now = ((double) clock() / CLK\_TCK) \* 1000; } } now = ((double) clock() / CLK\_TCK) \* 1000; int rc=sendto(m\_oUDPSocket,(char\*)packet,size+12,0,(SOCKADDR\*)&m\_oUDPAddress,sizeof(SOCKADDR\_IN)); m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Packet sent at = %f.\\n", now ); m\_dPacketSendTime = ((double) clock() / CLK\_TCK) \* 1000; // milliseconds m\_dPacketSendTime += (m\_dPacketLengthMillis\*(1.0 - m\_dRTPOverlap)); m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Next send time = %f.\\n", m\_dPacketSendTime ); return size; } else return 0;
}
And one more thing is, on my Vista machine it works fine. The logger prints this: RTPEngine: Next send time = 53637.795918. RTPEngine: Sending data package with size 480 (excluding header). RTPEngine: Time now = 53628.000000, send time = 53637.795918. . . . RTPEngine: Time now = 53636.000000, send time = 53637.795918. RTPEngine: Time now = 53636.000000, send time = 53637.795918. RTPEngine: Time now = 53637.000000, send time = 53637.795918. RTPEngine: Time now = 536
I just found something else. A little disturbing. On our server machine (WIN XP) the Timer ALWAYS sleeps for 15.625ms. If it goes to sleep at all, that is. So this seems to be some kind of minimum time-slice (or a multiplied version of it). On my own developing computer (Vista) I don´t have theis kind of time-slices. The Timer sleeps for 9ms, then for 10ms and thereafter for 8ms. Does anybody now if one can manually control these time-slices? Souldrift
-
I just found something else. A little disturbing. On our server machine (WIN XP) the Timer ALWAYS sleeps for 15.625ms. If it goes to sleep at all, that is. So this seems to be some kind of minimum time-slice (or a multiplied version of it). On my own developing computer (Vista) I don´t have theis kind of time-slices. The Timer sleeps for 9ms, then for 10ms and thereafter for 8ms. Does anybody now if one can manually control these time-slices? Souldrift
There's some references on the web to the minimum timer period being 10 ms for uniprocessor systems and 15 ms for multiprocessor. It could also be different depending on whether it's 32 or 64 bit Windows. The minimum on my system seems to be 15 ms - that's on Vista 32-bit with a dual-core processor.
-
There's some references on the web to the minimum timer period being 10 ms for uniprocessor systems and 15 ms for multiprocessor. It could also be different depending on whether it's 32 or 64 bit Windows. The minimum on my system seems to be 15 ms - that's on Vista 32-bit with a dual-core processor.
Yeah, this would make our efforts kind of hopeless. But I just found out another little something. It doesn´t seem to be a Vista-XP-thing. But a network-thing. Whatever computer I use as a server, as long as the client comes in via network, the timer sleeps like 15.something millis. If server and client are on the same machine, there doesn´t seem to be a minimum time-slice (or it´s below what I saw so far). The timer sleeps as long (or brief) as I want. Souldrift
-
Good morning :), just a brief question. I got a multi-threaded program. Now is it possible to ensure that a certain thread at a certain point won´t lose its 'working permission'. Hm, don´t know if I expressed that correctly. I have a thread going into a function where it has to wait for a previously defined time, then go on. The thing is, it waits and waits and at some point its time slot is taken away. When it is given the next slot, though, the time it has waited for has 'long' passed. And thus it´s always too late. The code in question is:
int RTPEngine::SendRTPPacket( BYTE* data, int size )
{
if( data && size > 0 && m_pHeader )
{
m_pLogger->Out(Logger::DEBUG, "RTPEngine: Sending data package with size %d (excluding header).\n", size);BYTE\* packet = new BYTE\[size+12\]; BYTE\* headerBytes = m\_pHeader->GetInc(); for( int i = 0; i < 12; i++ ) { packet\[i\] = headerBytes\[i\]; } for( int i = 0; i < size; i++ ) { packet\[i+12\] = data\[i\]; } double now = 0.0; // milliseconds if( m\_dPacketSendTime != 0.0 ) { now = ((double) clock() / CLK\_TCK) \* 1000; // milliseconds int tmp = 0; //m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Time now = %f.\\n", now ); while( now <= m\_dPacketSendTime ) { if( tmp >= 20 ) { m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Time now = %f, send time = %f.\\n", now, m\_dPacketSendTime ); tmp = 0; } tmp++; now = ((double) clock() / CLK\_TCK) \* 1000; } } now = ((double) clock() / CLK\_TCK) \* 1000; int rc=sendto(m\_oUDPSocket,(char\*)packet,size+12,0,(SOCKADDR\*)&m\_oUDPAddress,sizeof(SOCKADDR\_IN)); m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Packet sent at = %f.\\n", now ); m\_dPacketSendTime = ((double) clock() / CLK\_TCK) \* 1000; // milliseconds m\_dPacketSendTime += (m\_dPacketLengthMillis\*(1.0 - m\_dRTPOverlap)); m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Next send time = %f.\\n", m\_dPacketSendTime ); return size; } else return 0;
}
And one more thing is, on my Vista machine it works fine. The logger prints this: RTPEngine: Next send time = 53637.795918. RTPEngine: Sending data package with size 480 (excluding header). RTPEngine: Time now = 53628.000000, send time = 53637.795918. . . . RTPEngine: Time now = 53636.000000, send time = 53637.795918. RTPEngine: Time now = 53636.000000, send time = 53637.795918. RTPEngine: Time now = 53637.000000, send time = 53637.795918. RTPEngine: Time now = 536
-
Good morning :), just a brief question. I got a multi-threaded program. Now is it possible to ensure that a certain thread at a certain point won´t lose its 'working permission'. Hm, don´t know if I expressed that correctly. I have a thread going into a function where it has to wait for a previously defined time, then go on. The thing is, it waits and waits and at some point its time slot is taken away. When it is given the next slot, though, the time it has waited for has 'long' passed. And thus it´s always too late. The code in question is:
int RTPEngine::SendRTPPacket( BYTE* data, int size )
{
if( data && size > 0 && m_pHeader )
{
m_pLogger->Out(Logger::DEBUG, "RTPEngine: Sending data package with size %d (excluding header).\n", size);BYTE\* packet = new BYTE\[size+12\]; BYTE\* headerBytes = m\_pHeader->GetInc(); for( int i = 0; i < 12; i++ ) { packet\[i\] = headerBytes\[i\]; } for( int i = 0; i < size; i++ ) { packet\[i+12\] = data\[i\]; } double now = 0.0; // milliseconds if( m\_dPacketSendTime != 0.0 ) { now = ((double) clock() / CLK\_TCK) \* 1000; // milliseconds int tmp = 0; //m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Time now = %f.\\n", now ); while( now <= m\_dPacketSendTime ) { if( tmp >= 20 ) { m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Time now = %f, send time = %f.\\n", now, m\_dPacketSendTime ); tmp = 0; } tmp++; now = ((double) clock() / CLK\_TCK) \* 1000; } } now = ((double) clock() / CLK\_TCK) \* 1000; int rc=sendto(m\_oUDPSocket,(char\*)packet,size+12,0,(SOCKADDR\*)&m\_oUDPAddress,sizeof(SOCKADDR\_IN)); m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Packet sent at = %f.\\n", now ); m\_dPacketSendTime = ((double) clock() / CLK\_TCK) \* 1000; // milliseconds m\_dPacketSendTime += (m\_dPacketLengthMillis\*(1.0 - m\_dRTPOverlap)); m\_pLogger->Out( Logger::DEBUG, "RTPEngine: Next send time = %f.\\n", m\_dPacketSendTime ); return size; } else return 0;
}
And one more thing is, on my Vista machine it works fine. The logger prints this: RTPEngine: Next send time = 53637.795918. RTPEngine: Sending data package with size 480 (excluding header). RTPEngine: Time now = 53628.000000, send time = 53637.795918. . . . RTPEngine: Time now = 53636.000000, send time = 53637.795918. RTPEngine: Time now = 53636.000000, send time = 53637.795918. RTPEngine: Time now = 53637.000000, send time = 53637.795918. RTPEngine: Time now = 536
One last thought. I just tried to not let the thread sleep or create a wait object or anything. I simply went into a while-loop. Endlessly. Where I fetched and printed the system time. This was the result
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000 -
One last thought. I just tried to not let the thread sleep or create a wait object or anything. I simply went into a while-loop. Endlessly. Where I fetched and printed the system time. This was the result
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000Souldrift wrote:
And so on ... it always jumps 15,6ms forward
Here's what Mark Russinovitch and David Solomon say in Windows Internals
_
On Windows 2000 Professional and Windows XP, threads run by default for 2 clock intervals; on Windows Server systems, by default, a thread runs for 12 clock intervals. The rationale for the longer default value on server systems is to minimize context switching. By having a longer quantum, server applications that wake up as the result of a client request have a better chance of completing the request and going back into a wait state before their quantum ends
The length of the clock interval varies according to the hardware platform. The frequency of the clock interrupts is up to the HAL, not the kernel. For example, the clock interval for most x86 uniprocessors is about 10 milliseconds and for most x86 multiprocessors it is about 15 milliseconds. (The actual clock rate is not exactly a round number of milliseconds—see the following experiment for a way to check the actual clock interval.)
EXPERIMENT: Determining the Clock Interval Frequency
The Windows GetSystemTimeAdjustment function returns the clock interval. To determine the clock interval, download and run the Clockres program[^] from http://www.sysinternals.com.
_
That kind of confirms what you're seeing (and what I see - which is 15.625, or 500/32). HOWEVER!!!! I steered you wrong with waitable timers. I mistook them for a TimerQueueTimer in my memory. Try this:
#include <Windows.h>
#include <tchar.h>
#include <iostream>void ReportTime(const char* message, LONGLONG const& when)
{
std::cout << message << double(when)/10000.0 << std::endl;
}LONG count;
LARGE_INTEGER liStart, liEnd, liFreq;VOID CALLBACK DoSendHere(__in_opt LPVOID lpArgToCompletionRoutine,
__in DWORD dwTimerLowValue,
__in DWORD dwTimerHighValue)
{
QueryPerformanceCounter(&liEnd);
count++;
}void SendLoop()
{
HANDLE hTimerQueue = CreateTimerQueue();
HANDLE hTimer;
count = 0;
CreateTimerQueueTimer(&hTimer, hTimerQueue, (WAITORTIMERCALLBACK)&DoSendHere, 0 , 1, 1, WT_EXECU -
One last thought. I just tried to not let the thread sleep or create a wait object or anything. I simply went into a while-loop. Endlessly. Where I fetched and printed the system time. This was the result
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781458000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000, send time = 12891115378155.598000.
RTPEngine: Time now = 128911153781614000.000000Souldrift wrote:
it always jumps 15,6ms forward
I doubt the granularity and accuracy of the time value returned by
::GetSystemTimeAsFileTime()
. Even though theFILETIME
structure is a time value where the least significant bit represents 100 nanoseconds, it doesn't mean that it has an accuracy of 100 nanosecs. It's like looking at your watch, measuring a time with the needle showing seconds and then multiplying the value by 1,000,000 and claim you measured with microsecond accuracy. For time measurements of this kind you should you the performance timer;::QueryPerformanceCounter()
and::QueryPerformanceFrequency()
. It will give you the best accuracy available on your hardware. Read here[^] for more info on the high resolution performance counter."It's supposed to be hard, otherwise anybody could do it!" - selfquote
"High speed never compensates for wrong direction!" - unknown -
Souldrift wrote:
And so on ... it always jumps 15,6ms forward
Here's what Mark Russinovitch and David Solomon say in Windows Internals
_
On Windows 2000 Professional and Windows XP, threads run by default for 2 clock intervals; on Windows Server systems, by default, a thread runs for 12 clock intervals. The rationale for the longer default value on server systems is to minimize context switching. By having a longer quantum, server applications that wake up as the result of a client request have a better chance of completing the request and going back into a wait state before their quantum ends
The length of the clock interval varies according to the hardware platform. The frequency of the clock interrupts is up to the HAL, not the kernel. For example, the clock interval for most x86 uniprocessors is about 10 milliseconds and for most x86 multiprocessors it is about 15 milliseconds. (The actual clock rate is not exactly a round number of milliseconds—see the following experiment for a way to check the actual clock interval.)
EXPERIMENT: Determining the Clock Interval Frequency
The Windows GetSystemTimeAdjustment function returns the clock interval. To determine the clock interval, download and run the Clockres program[^] from http://www.sysinternals.com.
_
That kind of confirms what you're seeing (and what I see - which is 15.625, or 500/32). HOWEVER!!!! I steered you wrong with waitable timers. I mistook them for a TimerQueueTimer in my memory. Try this:
#include <Windows.h>
#include <tchar.h>
#include <iostream>void ReportTime(const char* message, LONGLONG const& when)
{
std::cout << message << double(when)/10000.0 << std::endl;
}LONG count;
LARGE_INTEGER liStart, liEnd, liFreq;VOID CALLBACK DoSendHere(__in_opt LPVOID lpArgToCompletionRoutine,
__in DWORD dwTimerLowValue,
__in DWORD dwTimerHighValue)
{
QueryPerformanceCounter(&liEnd);
count++;
}void SendLoop()
{
HANDLE hTimerQueue = CreateTimerQueue();
HANDLE hTimer;
count = 0;
CreateTimerQueueTimer(&hTimer, hTimerQueue, (WAITORTIMERCALLBACK)&DoSendHere, 0 , 1, 1, WT_EXECUBah, you beat me to it... :-\
"It's supposed to be hard, otherwise anybody could do it!" - selfquote
"High speed never compensates for wrong direction!" - unknown -
Bah, you beat me to it... :-\
"It's supposed to be hard, otherwise anybody could do it!" - selfquote
"High speed never compensates for wrong direction!" - unknownSorrreeeee :-O
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
Sorrreeeee :-O
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
:laugh:
"It's supposed to be hard, otherwise anybody could do it!" - selfquote
"High speed never compensates for wrong direction!" - unknown -
Souldrift wrote:
And so on ... it always jumps 15,6ms forward
Here's what Mark Russinovitch and David Solomon say in Windows Internals
_
On Windows 2000 Professional and Windows XP, threads run by default for 2 clock intervals; on Windows Server systems, by default, a thread runs for 12 clock intervals. The rationale for the longer default value on server systems is to minimize context switching. By having a longer quantum, server applications that wake up as the result of a client request have a better chance of completing the request and going back into a wait state before their quantum ends
The length of the clock interval varies according to the hardware platform. The frequency of the clock interrupts is up to the HAL, not the kernel. For example, the clock interval for most x86 uniprocessors is about 10 milliseconds and for most x86 multiprocessors it is about 15 milliseconds. (The actual clock rate is not exactly a round number of milliseconds—see the following experiment for a way to check the actual clock interval.)
EXPERIMENT: Determining the Clock Interval Frequency
The Windows GetSystemTimeAdjustment function returns the clock interval. To determine the clock interval, download and run the Clockres program[^] from http://www.sysinternals.com.
_
That kind of confirms what you're seeing (and what I see - which is 15.625, or 500/32). HOWEVER!!!! I steered you wrong with waitable timers. I mistook them for a TimerQueueTimer in my memory. Try this:
#include <Windows.h>
#include <tchar.h>
#include <iostream>void ReportTime(const char* message, LONGLONG const& when)
{
std::cout << message << double(when)/10000.0 << std::endl;
}LONG count;
LARGE_INTEGER liStart, liEnd, liFreq;VOID CALLBACK DoSendHere(__in_opt LPVOID lpArgToCompletionRoutine,
__in DWORD dwTimerLowValue,
__in DWORD dwTimerHighValue)
{
QueryPerformanceCounter(&liEnd);
count++;
}void SendLoop()
{
HANDLE hTimerQueue = CreateTimerQueue();
HANDLE hTimer;
count = 0;
CreateTimerQueueTimer(&hTimer, hTimerQueue, (WAITORTIMERCALLBACK)&DoSendHere, 0 , 1, 1, WT_EXECUUhh, thanks, I´ll try that out in a moment. Thanks for the writings on Windows Internals. Who could have known such a thing :). Very interesting. Two things, though. Why do you set a sleep time of 65ms (instead of infinite)? And I don´t see why this should circumvent the 15ms time-slice. QueryPerformanceCounter might 'see' higher resolution, but if the thread sleeps for 15ms, there´s nothing to see? Or is there? Souldrift
-
Uhh, thanks, I´ll try that out in a moment. Thanks for the writings on Windows Internals. Who could have known such a thing :). Very interesting. Two things, though. Why do you set a sleep time of 65ms (instead of infinite)? And I don´t see why this should circumvent the 15ms time-slice. QueryPerformanceCounter might 'see' higher resolution, but if the thread sleeps for 15ms, there´s nothing to see? Or is there? Souldrift
The 65ms is just an example time - it can't be infinite because I want it to terminate :-) The thing that's seeing past the 15.625 timer resolution is the TimerQueueTimer. That has a resolution of 1ms. The program is intended to show that the timer callback is called with a resolution of 1ms, so could be used in your case, so long as your thread can remain the active thread.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
The 65ms is just an example time - it can't be infinite because I want it to terminate :-) The thing that's seeing past the 15.625 timer resolution is the TimerQueueTimer. That has a resolution of 1ms. The program is intended to show that the timer callback is called with a resolution of 1ms, so could be used in your case, so long as your thread can remain the active thread.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
Okay, I thought so (after some thinking). Now if you will bear with me one more time, I´m not quite sure how to understand (handle) this regarding my case. For example if I use this (cause 9ms are appx. the time I need to wait before sending)
CreateTimerQueueTimer(&hTimer, hTimerQueue, (WAITORTIMERCALLBACK)&DoSendHere, 0 , 9, 1, WT_EXECUTEINTIMERTHREAD);
QueryPerformanceCounter(&liStart);
::SleepEx(65, TRUE);The callback func should with a 65ms sleep be called like 7 times. Though my log shows 54. I guess, this is because the timer doesn´t stop after my sleep or my sending. So the next question would be, how do I stop it? I know, i doesn´t even have to be periodic for what I need (so it would stop by itself), but I´m trying to understand the structure. I added a DeleteTimerQueueEx( hTimerQueue, NULL ); but it crashes now at that point. Souldrift Edit: And why does it not call the callback func when I take away the sleepEx()?? Is it dependant on the thread being asleep? If I do this
CreateTimerQueueTimer(&hTimer, hTimerQueue, (WAITORTIMERCALLBACK)&DoSendHere, 0 , 1, 0, WT_EXECUTEINTIMERTHREAD);
QueryPerformanceCounter(&liStart);
::SleepEx(10, TRUE);it doesn´t enter, either.
modified on Monday, July 6, 2009 4:32 AM
-
Okay, I thought so (after some thinking). Now if you will bear with me one more time, I´m not quite sure how to understand (handle) this regarding my case. For example if I use this (cause 9ms are appx. the time I need to wait before sending)
CreateTimerQueueTimer(&hTimer, hTimerQueue, (WAITORTIMERCALLBACK)&DoSendHere, 0 , 9, 1, WT_EXECUTEINTIMERTHREAD);
QueryPerformanceCounter(&liStart);
::SleepEx(65, TRUE);The callback func should with a 65ms sleep be called like 7 times. Though my log shows 54. I guess, this is because the timer doesn´t stop after my sleep or my sending. So the next question would be, how do I stop it? I know, i doesn´t even have to be periodic for what I need (so it would stop by itself), but I´m trying to understand the structure. I added a DeleteTimerQueueEx( hTimerQueue, NULL ); but it crashes now at that point. Souldrift Edit: And why does it not call the callback func when I take away the sleepEx()?? Is it dependant on the thread being asleep? If I do this
CreateTimerQueueTimer(&hTimer, hTimerQueue, (WAITORTIMERCALLBACK)&DoSendHere, 0 , 1, 0, WT_EXECUTEINTIMERTHREAD);
QueryPerformanceCounter(&liStart);
::SleepEx(10, TRUE);it doesn´t enter, either.
modified on Monday, July 6, 2009 4:32 AM
Souldrift wrote:
CreateTimerQueueTimer(&hTimer, hTimerQueue, (WAITORTIMERCALLBACK)&DoSendHere, 0 , 9, 1, WT_EXECUTEINTIMERTHREAD);
You're asking for a timer with an initial delay of 9ms and periodic delays after that of 1ms.
Souldrift wrote:
DeleteTimerQueueEx( hTimerQueue, NULL );
Think that should be
DeleteTimerQueueTimer( hTimerQueue, hTimer, 0 );
. That worked for me, anyway.Souldrift wrote:
And why does it not call the callback func when I take away the sleepEx()?? Is it dependant on the thread being asleep?
The thread needs to be in an alertable state - look at the MSDN documentation[^] for what that means.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p