7 votes

Comment puis-je utiliser CreateTimerQueueTimer pour créer un timer haute résolution en C# ?

J'ai utilisé une dll multimédia Windows pour créer un timer haute résolution avec

timSetEvent()

Mais le timeSetEvent() recommande l'utilisation de :

CreateTimerQueueTimer()

Comment puis-je utiliser CreateTimerQueueTimer() pour exécuter une méthode toutes les 10 millisecondes en C# ?

9voto

MusiGenesis Points 49273

Voici un lien vers un wrapper C# pour CreateTimerQueueTimer :

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

(faire défiler vers le bas jusqu'au dernier message de Hobz pour la classe type)

Je viens de l'essayer moi-même et cela fonctionne bien. Une chose que vous devrez ajouter, cependant, c'est un appel à timeBeginPeriod(1) avant de démarrer la minuterie afin de régler votre système en haute résolution. timeSetEvent appels timeBeginPeriod en interne, c'est pourquoi certaines personnes pensent à tort qu'il crée un timer à plus haute résolution.

3voto

ShuggyCoUk Points 24204

Le rappel passé à CreateTimerQueueTimer est censé être un non géré qui existera pendant toute la durée de vie des rappels. Le délégué géré peut se déplacer dans la mémoire, mais le stub sous-jacent créé par le marshalling ne le fera pas, il n'est donc pas nécessaire d'épingler le délégué . Il est cependant nécessaire d'empêcher le délégué d'être ramassé par les éboueurs, car le pointeur du code non géré n'est pas suffisant pour le maintenir en vie. Vous devez donc vous assurer que le délégué est maintenu en vie par une référence gérée (peut-être par l'utilisation de GCHandle

Le paramètre PVOID transmis à la fonction de rappel doit être fixé en mémoire car, là encore, la fonction non gérée s'attend à ce qu'il ne soit pas déplacé après le retour de la fonction. Dans .Net, cette fixation se fait (efficacement) automatiquement mais seulement pour la durée de vie de la fonction appelée. Ainsi, si vous utilisez une référence à un objet géré (par exemple en obtenant un IntPtr vers lui), l'objet sous-jacent doit être épinglé (une fois encore, le GCHandle peut être utilisé pour cela d'une manière subtilement différente). Pour voir si c'est le problème, essayez d'utiliser IntPtr.Zero comme paramètre pour tester si cela fonctionne.

Si cela résout les problèmes, vous devrez soit allouer votre paramètre en tant qu'octets bruts dans le tas non géré (et le marshaller en conséquence), soit utiliser un type blittable qu'il est sûr de mettre dans quelque chose de taille PVOID (comme un Int32), soit utiliser la technique GCHandle ci-dessus pour maintenir un pointeur stable vers une instance gérée, ce qui aura des implications significatives en termes de performances si cela n'est pas fait correctement.

2voto

Anonymous Points 21

Il est préférable d'utiliser timeSetEvent car les résultats sont plus cohérents. Sur un matériel moderne moyen, pour de petits intervalles, les écarts de longueur des intervalles sont environ dix fois moins importants que lors de l'utilisation de CreateTimerQueueTimer. Et cela en supposant que vous n'ayez pas oublié d'augmenter la résolution du timer avant d'appeler CreateTimerQueueTimer, sinon la différence serait encore plus grande. Utilisez donc plutôt timeSetEvent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X