Einen Thread nach bestimmter Zeit unterbrechen
-
Stimmt! Dann werde ich mal ich mal nach einer passenden Zyklenanzahl sehen. Danke!
-
Die bekommst du direkt mit der oben verlinkten Funktion
QueryThreadCycleTime() sollte dir die Anzahl der Zyklen die ein Thread netto gerechnet hat liefern.
-
Ja das war mir klar ;-). Jetzt sehe ich aber gerade, das die erst ab WinVista unterstĂŒtzt wird. Ich bin hier mit XP unterwegs... mal sehen!
-
GetThreadTimes() ...
-
Stimmt, damit gehts auch.
-
Nimm mal lieber QueryPerformanceCounter,.. dieser gibt dir auch die Laufzeit in ns zurĂŒck,...
Hier ein beispiel:
#include <time.h> #include <windows.h> namespace _stde{ //################################################################################################## // // CPUTICKSSTRUCT // Struct Contains informations about the Cpu ticks to calculate RunTime // //################################################################################################## typedef struct _cpu_ticks_struct // Struct Contains informations about the Cpu ticks to calculate RunTime { double dLastTime; //Last Time wich has been setted LARGE_INTEGER liLastCount; //Last Count number which has been setted double dCheckTime; //Time which has been checked double dReturn; //Return value LARGE_INTEGER nFreq; //Frequency LARGE_INTEGER nCount; //Tick Count double GetCPUTicks(void); //Procedure to Calulate the Framerate double GetMilliseconds(void); _cpu_ticks_struct(); //Ctor ~_cpu_ticks_struct(); //Dtor }CPUTICKSSTRUCT,*LPCPUTICKSSTRUCT; //Struct Contains informations about the Cpu ticks to calculate RunTime typedef CPUTICKSSTRUCT CTS; //Make it a bit shorter typedef LPCPUTICKSSTRUCT LPCTS; //Make it a bit shorter } //################################################################################################## // // CPUTICKSSTRUCT // Struct Contains informations about the Cpu ticks to calculate RunTime // //################################################################################################## _stde::_cpu_ticks_struct::_cpu_ticks_struct() { ZeroMemory(this,sizeof(_stde::CPUTICKSSTRUCT)); this->dCheckTime=5.0; }; _stde::_cpu_ticks_struct::~_cpu_ticks_struct() { ZeroMemory(this,sizeof(_stde::CPUTICKSSTRUCT)); }; double _stde::_cpu_ticks_struct::GetCPUTicks() { LARGE_INTEGER counter={0}; // check for a new frequency once every 5 seconds // note: this is in case ACPI, etc. alters it if((this->nFreq.QuadPart == 0) || (this->dCheckTime < (this->dReturn))) { this->dCheckTime = this->dReturn + 5.0; // avoid a division by zero by returning zero on error if(!QueryPerformanceFrequency(&(this->nFreq))) return 0.0; } // use the ratio of tick amount divided by frequency to find the hertz QueryPerformanceCounter(&(this->nCount)); if(this->liLastCount.QuadPart!=0){ counter.QuadPart=this->nCount.QuadPart-this->liLastCount.QuadPart; this->dReturn = ((double)counter.QuadPart / (double)this->nFreq.QuadPart); }; this->liLastCount=this->nCount; if(this->dReturn!=0){this->dReturn=double(1)/(this->dReturn);}; return (this->dReturn); }; double _stde::_cpu_ticks_struct::GetMilliseconds(void) { return (1000/(this->GetCPUTicks()));}; };
Bedenke das die Erzeugung eines Threads weitaus lÀnger dauert (zwischen 0,5 ms bis 2,5ms, vom Aufruf CreateThread bis zum fertigen Eintritt in die THREAD_PROC) als der Kontextwechsel,...
grĂŒĂe
-
zeusosc schrieb:
Bedenke das die Erzeugung eines Threads weitaus lÀnger dauert (zwischen 0,5 ms bis 2,5ms, vom Aufruf CreateThread bis zum fertigen Eintritt in die THREAD_PROC) als der Kontextwechsel,...
Ich zweifle GANZ STARK daran, dass die 0.5 - 2.5 ms der Wirklichkeit entsprechen.
(Dass es lĂ€nger als der Kontextwechsel dauert, damit wirst du allerdings vermutlich Recht haben - wĂŒrde mich zumindest stark wundern wenn nicht)
-
Haben wir auf zwei systemen getestet:
Aus Thread A mit Prio -15 bis 15 wird ein Thread B gestartet mit Prio -15 bis 15GezÀhlt wurde die Zeit (Per QueryPerformanceCounter)
von VOR
CreateThread
Bis Nach
WaitForSingleEvent()Der Event wurde nach Eintritt in die Threadfunk gesetzt.
Ein paar tausend DurchlÀufe bei Nominallast des Systems,
Die Zeit aufgetragen als DensityPlot ĂŒber ThreadPrio A u BGetestet wurden:
Core2Duo P8400 @ 2.26 Ghz 2.27 Ghz 2GBRam Max: 2250”s Min: >460”s
(ok es gab noch eine klitzekleine spitze bei Prio -15,5 bei rund 3593”s)
AMD Athlon XP 2200+ 1.80 Ghz 1.5 GBRam Max: >4040”s Min: >907”s
-
@zeusosc:
Kann ich nicht ganz nachvollziehen.
Ich hab jetzt keinen so ausfĂŒhrlichen Test mit min/max/avg gemacht und auch nur mit PrioritĂ€t 0, aber da komme ich auf 110 ~ 140ms fĂŒr 1000 Threads, also so 0.11 ~ 0.14ms pro Thread.
Also etwa Faktor 4 - 20 schneller als deine Zahlen.Ganz einfacher Test, ein Thread startet immer den nÀchsten, der letzte setzt den Event:
#include <iostream> #include <Windows.h> #include <process.h> #pragma comment(lib, "winmm") HANDLE event = 0; size_t counter = 0; unsigned __stdcall ThreadFn(void*); void StartNextThread() { UINT threadId = 0; HANDLE thread = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, &ThreadFn, 0, 0, &threadId)); // auch mit CreateThread() probiert, Àndert fast nix (minimal schneller mit CreateThread()) ::CloseHandle(thread); } unsigned __stdcall ThreadFn(void*) { if (counter == 0) ::SetEvent(event); else { counter--; StartNextThread(); } return 0; } void Run() { ::ResetEvent(event); counter = 1000; StartNextThread(); ::WaitForSingleObject(event, INFINITE); } int main() { //::SetProcessAffinityMask(::GetCurrentProcess(), 1); // war testweise drinnen, Àndert aber kaum was (minimal langsamer mit) event = ::CreateEventW(0, true, false, 0); ::timeBeginPeriod(1); // war testweise draussen, Àndert aber so-gut-wie nix for (size_t i = 0; i < 100; i++) { ::SetThreadPriority(::GetCurrentThread(), 0); DWORD t0 = ::timeGetTime(); Run(); DWORD t1 = ::timeGetTime(); std::cout << t1 - t0 << "\n"; } ::CloseHandle(event); }
System: Windows 7 64 Bit, Core2 Quad Q6600 (4 * 2.4 GHz), 8 GB RAM.
Das misst jetzt natĂŒrlich was anderes als dein Test.
Dein Test misst ja die Zeit die zum Erstellen und "Loslaufen" des neuen Threads benötigt wird + die Zeit die vom SetEvent() bis zum Aufwachen des startenden Threads vergeht.
Meiner misst nur die Zeit die zum Erstellen und "Loslaufen" des neuen Threads benötigt wird, weil der ja gleich wieder den nÀchsten startet, und nur zum Schluss 1x der "Eltern-Thread" aufgeweckt wird.
ps: solche Tests muss man frei laufen lassen. Wenn ich die Release Version unter Visual Studio laufen lasse, ist die mehr als Faktor 10 langsamer! Sollte klar sein, ich sag's nur vorsichtshalber trotzdem dazu.
-
So, ich hab' das ganze noch schnell auf das andere Schema umgestellt:
void StartNextThread() { UINT threadId = 0; HANDLE thread = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, &ThreadFn, 0, 0, &threadId)); ::CloseHandle(thread); } unsigned __stdcall ThreadFn(void*) { counter--; ::SetEvent(event); return 0; } void Run() { ::ResetEvent(event); counter = 1000; while (counter > 0) { StartNextThread(); ::WaitForSingleObject(event, INFINITE); ::ResetEvent(event); } }
Zeit liegt immer noch bei ~~ 0.13 ms pro Thread.
Selbst wenn ich nicht nur auf den Event, sondern auf das Thread-Object selbst warte, Àndert sich nichts an der gemessenen Zeit:void Run() { counter = 1000; while (counter > 0) { ::ResetEvent(event); UINT threadId = 0; HANDLE thread = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, &ThreadFn, 0, 0, &threadId)); ::WaitForSingleObject(event, INFINITE); ::WaitForSingleObject(thread, INFINITE); ::CloseHandle(thread); } }
EDIT:
Und nochmal auf nem Athlon 4850e (2 * 2.5 GHz) getestet, Windows 2008 R2 64 Bit, 4 GB RAM: 0.095 ~ 0.11 ms pro Thread.
Es wĂ€re natĂŒrlich möglich dass Ă€ltere bzw. 32 Bit Windows-Versionen hier schlechter abschneiden. Hab ich aber grad keine da zum testen...
EDIT2:
Core i5 2500T (4 * 2.3 ~ 3.3 GHz), Windows 7 64 Bit, 8 GB RAM: 0.043 ~ 0.049 ms pro Thread.