Timer mit APC-Aufruf
-
Hi,
ich hab hier mal ein kleines Testprogramm geschrieben. Allerdings verstehe ich nicht, warum er nicht in TimerApc(...) springt, obwohl der Timer signalisiert wird.
#include <iostream> #include <iomanip> using namespace std; #include "Windows.h" #include "Time.h" #define NAME_TI "Name_Ti_Test" HANDLE hTi_Test = NULL; void PrintTime (char *pcLabel) //die Ausgabe von Zeitstempeln { if (pcLabel == NULL) return; SYSTEMTIME sTime; GetSystemTime (&sTime); cout << endl << endl << pcLabel << ": " << setw (2) << setfill('0') << (sTime.wHour+1) << ":" << sTime.wMinute << ":" << sTime.wSecond << "," << setw (3) << setfill('0') << sTime.wMilliseconds; return; } //----------------------------------------------------------------------------- void APIENTRY TimerApc (LPVOID, DWORD, DWORD) //<- hier will er nicht reinspringen { PrintTime ("ENDE"); return; } //----------------------------------------------------------------------------- void ResetTimer(LARGE_INTEGER& rliTime) //Timer mit dem neuen Wert starten { if (hTi_Test != NULL) { SetWaitableTimer (hTi_Test, &rliTime, 0, (PTIMERAPCROUTINE)TimerApc, NULL, false); PrintTime ("START"); } return; } //----------------------------------------------------------------------------- int main (int argc, char **argv) { hTi_Test = CreateWaitableTimer (NULL, false, NAME_TI); if (hTi_Test == NULL) { cout << endl << "Erstellung des Timers fehlgeschlagen!"; return -1; } SYSTEMTIME sTime; LARGE_INTEGER liTime; liTime.QuadPart = 1; while (liTime.QuadPart != 0) { memset (&liTime, 0, sizeof(liTime)); cout << endl << "Timerlaenge angeben [in 100ns]: "; cin >> liTime.QuadPart; //negative Werte eingeben if (liTime.QuadPart == 0) break; ResetTimer (liTime); if ((WaitForSingleObject (hTi_Test, 3000)) != WAIT_TIMEOUT) cout << endl << "Timer signalisiert!" << endl; } CancelWaitableTimer (hTi_Test); CloseHandle (hTi_Test); return 0; }Sicher ich könnte auch einen Thread auf das Ablaufen des Timers warten lassen, aber die Lösung für mein Problem über den Apc-Aufruf, wäre wesentlich eleganter.
Als Compiler benutze ich den, der von Borland bei der BCB6-Umgebung mitgeliefert wird. Ich weiss allerdings nicht, in wie weit das wichtig ist.Hat jemand von euch damit Erfahrung?
Maffe
-
WaitForSingleObjectEx ist die benötigte Funktion. WaitForSingleObject (ohne ex) wartet nicht auf APC.
-
Ich würde mal vemuten, weil Du versuchst, eine Windows-API in einem Consolenprogramm zu verwenden. APIENTRY ist ein Format, das für Windows-Programme genutzt wird, Deine "int main" ist aber nur ein DOS-Format.
TimerApc erwartet drei Parameter (LPVOID, DWORD, DWORD), die Du beim aufruf nicht übergibst.
-
@mgs_:
Ich hab das Ganze schon auf WaitForSingleObjectEx geändert. Funktioniert trotzdem nicht.@Electronix:
Ich brauch ja auch nicht unbedingt, was übergeben, bei einem solch "einfachen" Aufruf. Das mit dem DOS ist ein Argument. Müsste dann nicht aber der Compiler sich beschweren?
-
Ich hab's jetzt so geändert. Und so funktionierts.
int main (int argc, char **argv) { hTi_Test = CreateWaitableTimer (NULL, false, NAME_TI); if (hTi_Test == NULL) { cout << endl << "Erstellung des Timers fehlgeschlagen!"; return -1; } SYSTEMTIME sTime; LARGE_INTEGER liTime; liTime.QuadPart = 1; while (liTime.QuadPart != 0) { memset (&liTime, 0, sizeof(liTime)); cout << endl << "Timerlaenge angeben [in 100ns]: "; cin >> liTime.QuadPart; if (liTime.QuadPart == 0) break; ResetTimer (liTime); if ((SleepEx (3000, true)) == 0) cout << endl << endl << "Timer noch nicht abgelaufen!" << endl; else cout << endl << endl << "APC-Aufruf!" << endl; } CancelWaitableTimer (hTi_Test); CloseHandle (hTi_Test); return 0; }Der Grund war:
Jeffrey Richter - Microsoft Windows, Programmierung für Experten schrieb:
HANDLE hTimer = CreateWaitableTimer (....);
SetWaitableTimer (hTimer, ..., TimerAPCRoutine, ...);
WaitForSingleObjectEx (hTimer, INFINITE, true);Derartiger Code ist zu vermeiden, da der Aufruf von WaitForSingleObjectEx in Wirklichkeit ein zweifaches Warten impliziert, einmal per Alarmierung und zum zweiten über ein Handle für ein Kernel-Objekt. Wenn der Zeitgeber in den signalisierten Zustand wechselt, war das Warten erfolgreich und der Thread wird aktiviert. Letzteres bewirkt ein Verlassen des alarmierbaren Zustands, weshalb die APC-Prozedur nicht aufgerufen wird. [...]