Вопрос по c# – Как я могу использовать CreateTimerQueueTimer для создания таймера высокого разрешения в C #?

7

Я использовал мультимедийную библиотеку Windows для создания таймера высокого разрешения с

timSetEvent ()

НоtimeSetEvent() страница рекомендует использовать:

CreateTimerQueueTimer ()

Как я могу использовать CreateTimerQueueTimer () для выполнения метода каждые 10 миллисекунд в C #?

Ваш Ответ

3   ответа
2

потому что его результаты более последовательны. На среднем современном оборудовании для небольших интервалов отклонения в длине интервалов примерно в десять раз меньше, чем при использовании CreateTimerQueueTimer. И это при условии, что вы не забыли увеличить разрешение таймера перед вызовом CreateTimerQueueTimer, иначе разница будет еще больше. Так что вместо этого используйте timeSetEvent.

3

unmanaged функция, которая будет существовать в течение всего времени обратных вызовов. Управляемый делегат может перемещаться в памяти, ноосновная заглушка, созданная маршаллингом, не будет делать этого, поэтому нет необходимости прикреплять делегата, Однако существует необходимость предотвратить сборку мусора для делегата, поскольку указатель из неуправляемого кода недостаточен для его поддержки. Поэтому вы должны убедиться, что любой из делегатов остается в живых с помощью некоторой управляемой ссылки, поддерживаемой (возможно, с помощьюGCHandle

Параметр PVOID, который передается в функцию обратного вызова, должен быть зафиксирован в памяти, поскольку опять-таки неуправляемая функция ожидает, что она не будет перемещаться после ее возврата. В .Net это закрепление происходит (эффективно) автоматически, но только в течение срока действия вызываемой функции. Таким образом, если вы используете ссылку на некоторый управляемый объект (скажем, получая IntPtr к нему), базовый объект должен быть закреплен (опять же, GCHandle может использоваться для этого немного другим способом). Чтобы увидеть, если это проблема, попробуйте использовать IntPtr.Zero в качестве параметра, чтобы проверить, работает ли он.

Если это решает проблемы, вам нужно будет либо выделить свой параметр в виде необработанных байтов в неуправляемой куче (и, соответственно, маршал), используйте некоторый тип blittable, который можно безопасно поместить в нечто с размером PVOID (например, Int32), либо используйте метод GCHandle выше чтобы поддерживать стабильный указатель на управляемый экземпляр, это будет иметь значительные последствия для производительности, если сделано неправильно.

PInvoke определенно не поддерживает ссылки на делегатов для вас. Компилятор с радостью позволит вам вызвать CreateTimerQueueTimer и передатьnew TimerCallback(...) в качестве параметра. Это даже будет успешно выполняться некоторое время, пока делегат, которого вы создали сnew бывает мусор.
@MusiGenesis, это то, на что я ссылался "В .Net это почти наверняка произойдет с чем угодно, что вы передаете." Точно так же я не видел причин упоминать о необходимости сохранять ссылку, потому что P / Invoke делает это для вас, если это требуется:msdn.microsoft.com/en-us/23acw07k.aspx
Конечно, я научился этому нелегко. :)
@Musi, ну, ты имеешь в виду, если на делегат ссылаются как на обратный вызов после того, как функция PInvoke вернулась, да, я действительно поясню это в ответе.
Как правило, вам не нужно прикреплять делегаты, переданные функциям API, поскольку InteropServices обрабатывает эти вещи. Выdo необходимо убедиться, что ваше приложение поддерживает ссылку на делегат, чтобы оно не собирало мусор. Закрепление обычно необходимо только при передаче кусков памяти из управляемого мира в неуправляемый мир (который ожидает, что вещи останутся там, где они есть).
9

CreateTimerQueueTimer:

http://social.msdn.microsoft.com/Forums/en-CA/csharpgeneral/thread/822aed2d-dca0-4a8e-8130-20fab69557d2

(прокрутите вниз до последнего сообщенияHobz для образца класса)

Я только что попробовал это сам, и он отлично работает. Одна вещь, которую вам нужно добавить, это вызовtimeBeginPeriod(1) перед запуском таймера, чтобы установить систему в высоком разрешении.timeSetEvent звонкиtimeBeginPeriod внутренне, поэтому некоторые люди ошибочно полагают, что это создает таймер с более высоким разрешением.

@ MusiGenesis - я пытался использовать этот код, но получаю исключение stackoverlow. и что вы подразумеваете под "вызовом timeBeginPeriod (1)"? Я не смог найти такую функцию

Похожие вопросы