Szukam utworzyć wątek wywołania zwrotnego wysokiej częstotliwości. Zasadniczo potrzebuję funkcji do wykonania w regularnych odstępach wysokich częstotliwości (do 100 Hz). Zdaję sobie sprawę, że Windows ma normalny przekrój wykonania wątku to ~ 15ms. Chciałbym określić regularny interwał, który może być szybszy niż 15 ms.timing wysokiej częstotliwości .NET
Oto, co staram się osiągnąć. Mam urządzenie zewnętrzne, które musi być powiadamiane w określonym przedziale czasu. Odstęp jest zmienny w zależności od sytuacji. Oczekuję, że nigdy nie będę potrzebował więcej niż 100Hz (10ms) wskaźnika wiadomości.
Mogę oczywiście zaimplementować pętlę spinową, jednak miałem nadzieję, że istnieje rozwiązanie, które nie wymagałoby tak wielu zmarnowanych zasobów.
Podane linki do pytań/odpowiedzi nie rozwiązują tego problemu. Chociaż zgadzam się, że pytanie zostało zadane na kilka różnych sposobów, nie było dobrego rozwiązania, które faktycznie rozwiązało problem.
Większość udzielonych odpowiedzi mówi o użyciu stopera i ręcznym wykonywaniu zadania synchronizacji, które jest całkowicie zbyt intensywne dla procesora. Jedynymi realnymi rozwiązaniami były czasomierze multimedialne, które miały kilka pułapek, o czym wspomniał Haans. Znalazłem jednak inne rozwiązanie, które dodam poniżej. W tej chwili nie znam pułapek, ale planuję przeprowadzić testy i badania. Nadal jestem zainteresowany komentarzami dotyczącymi rozwiązania.
wezwanie WINAPI poprzez
BOOL WINAPI CreateTimerQueueTimer(
_Out_ PHANDLE phNewTimer,
_In_opt_ HANDLE TimerQueue,
_In_ WAITORTIMERCALLBACK Callback,
_In_opt_ PVOID Parameter,
_In_ DWORD DueTime,
_In_ DWORD Period,
_In_ ULONG Flags
);
i
BOOL WINAPI DeleteTimerQueueTimer(
_In_opt_ HANDLE TimerQueue,
_In_ HANDLE Timer,
_In_opt_ HANDLE CompletionEvent
);
Link - http://msdn.microsoft.com/en-us/library/windows/desktop/ms682485%28v=vs.85%29.aspx Używam PInvoke do osiągnięcia tego celu. Będzie to również wymagane w przypadku obsługi timerów multimedialnych.
Moja sygnatura typu PInvoke dla zainteresowanych. Pinvoke link
[DllImport("kernel32.dll")]
static extern bool CreateTimerQueueTimer(out IntPtr phNewTimer,
IntPtr TimerQueue, WaitOrTimerDelegate Callback, IntPtr Parameter,
uint DueTime, uint Period, uint Flags);
// This is the callback delegate to use.
public delegate void WaitOrTimerDelegate (IntPtr lpParameter, bool TimerOrWaitFired);
[DllImport("kernel32.dll")]
static extern bool DeleteTimerQueueTimer(IntPtr TimerQueue, IntPtr Timer,
IntPtr CompletionEvent);
użycie CreateTimerQueueTimer rozpocząć oddzwanianie timera. Użyj DeleteTimerQueueTimer, aby zatrzymać oddzwonienie timera. Jest to dość elastyczne, ponieważ można również tworzyć niestandardowe kolejki. Jednak najłatwiejszą implementacją, jeśli potrzebna jest tylko jedna instancja, byłoby użycie domyślnej kolejki.
Przetestowałem to rozwiązanie wzdłuż strony pierwszej używając stopera z pętlą spinową, a wyniki otrzymane w odniesieniu do synchronizacji były prawie identyczne. Jednak obciążenie procesora było znacząco różne na moim komputerze.
Stoper z pętli spinu - ~ 12-15% obciążenie CPU stałej (około 50% jednego z moich rdzeni) CreateTimerQueueTimer - ~ 3-4% CPU stałe obciążenie
czuję też utrzymanie kod będzie zmniejszono za pomocą opcji CreateTimerQueueTimer. ponieważ nie wymaga dodawania logiki do przepływu kodu.
Dzięki Hans, zawsze mogę docenić twoje odpowiedzi i porady. Znalazłem coś, co rozwiązuje mój problem podczas badania interfejsu API, o którym wspomniałeś. To jest użycie CreateTimerQueueTimer. Wydaje mi się, że daje mi to rozwiązanie z API, o którym wspomniałeś, ale bez wad związanych ze zmianą kolejności zdarzeń. Kolejną dodatkową korzyścią jest to, że pochodzi z pliku kernal32.dll. Wszelkie myśli dotyczące klasy API CreateTimerQueueTimer? – galford13x
Tak, jest to zalecana alternatywa dla timeSetEvent(). Nie wiem wystarczająco dużo o jego zdolności do zmiany częstotliwości przerywania zegara, będziesz musiał eksperymentować. –
Widząc, jak nie można podać więcej odpowiedzi. Zaznaczam to jako odpowiedź. Zapewnia rozwiązanie, które zadziała w mojej sytuacji. – galford13x