Ich habe eine .NET-Anwendung entwickelt, die ein Druckgerät mit 120 Hz abfragen muss. Die Standard-.NET-Timer scheinen nur bis zu 60 Hz zu erreichen, daher entschied ich mich, die Win32-API CreateTimerQueueTimer über PInvoke zu verwenden. Es funktioniert gut, aber die Debugging-Erfahrung ist sehr schlecht, weil die Timer sogar ausgelöst werden, wenn ich das Programm durchtrete, während das Programm gehalten wird. Ich schrieb ein minimales Beispiel in C und in C# und das unerwünschte Verhalten tritt nur auf C# auf. Das C-Programm erstellt die Timer-Callback-Threads nicht, während der Debugger das Programm angehalten hat. Kann mir jemand sagen, was ich tun kann, um das gleiche Debugging-Verhalten in C# zu erreichen?Windows Timer Queue Timer läuft nach .NET Breakpoint
C-Code:
#include <stdio.h>
#include <assert.h>
#include <Windows.h>
int counter = 0;
VOID NTAPI callback(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
{
printf("Just in time %i\n", counter++);
}
int main()
{
HANDLE timer;
BOOL success = CreateTimerQueueTimer(&timer, NULL, callback, NULL, 0, 1000, WT_EXECUTEDEFAULT);
assert(FALSE != success); // set breakpoint at this line and wait 10 seconds
Sleep(1000);
success = DeleteTimerQueueTimer(NULL, timer, NULL); // step to this line
assert(FALSE != success);
return 0;
}
Equivalent C# -Code:
using System;
using System.Runtime.InteropServices;
class TimerQueue
{
delegate void WAITORTIMERCALLBACK(IntPtr lpParameter, bool TimerOrWaitFired);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CreateTimerQueueTimer(
out IntPtr phNewTimer,
IntPtr TimerQueue,
WAITORTIMERCALLBACK Callback,
IntPtr Parameter,
uint DueTime,
uint Period,
uint Flags);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool DeleteTimerQueueTimer(
IntPtr TimerQueue,
IntPtr Timer,
IntPtr CompletionEvent);
static int counter = 0;
static void Callback(IntPtr lpParameter, bool TimerOrWaitFired)
{
Console.WriteLine("Just in time {0}", counter++);
}
static void Main(string[] args)
{
WAITORTIMERCALLBACK callbackWrapper = Callback;
IntPtr timer;
bool success = CreateTimerQueueTimer(out timer, IntPtr.Zero, callbackWrapper, IntPtr.Zero, 0, 1000, 0);
System.Diagnostics.Debug.Assert(false != success); // set breakpoint at this line and wait 10 seconds
System.Threading.Thread.Sleep(1000);
success = DeleteTimerQueueTimer(IntPtr.Zero, timer, IntPtr.Zero); // step to this line
System.Diagnostics.Debug.Assert(false != success);
}
}
By the way, ich weiß, es ist eine Race-Bedingung, wenn das ungeschützte Verwendung Zählervariable aus mehreren Threads, das ' Es ist momentan nicht wichtig. Der Schlaf für eine Sekunde ist unabhängig vom Warten nach dem Erreichen des Haltepunkts gemeint und scheint notwendig zu sein, da die Rückrufe nicht sofort in den Prozess eingereiht werden, selbst wenn das Programm in einem Debugger gestartet wird, aber nur nach einer kurzen Verzögerung.
Der Aufruf von DeleteTimerQueueTimer ist nicht wirklich notwendig, um mein Problem anzuzeigen, da es auftritt, bevor diese Zeile ausgeführt wird.
'// ... 10 Sekunden warten' gefolgt von 'Sleep (1000);' ist inkohärent. Meinst du, 10 Sekunden zu schlafen, aber entschieden, nur 1 zu schlafen? Hast du versehentlich nur 1 Sekunde geschlafen? Haben Sie einen anderen als den von Ihnen verwendeten Code eingegeben? – IInspectable
'die Timer werden sogar ausgelöst, wenn ich durch das Programm gehe. '- das und muss sein.und 'DeleteTimerQueueTimer' kann' FALSE' mit dem Fehler 'ERROR_IO_PENDING' zurückgeben – RbMm
Sie durchlaufen das Programm in eigenen Threads, während dieser Zeit Timer-Ereignissignal im Pool-Arbeits-Thread, wenn Kontext zu diesem Thread - Ihre' Callback' aufgerufen . das ist absolut normal und muss sein. Natürlich Debug-Code Bused auf periodische Timer-Ereignisse kann nicht einfach – RbMm