J'ai utilisé une dll multimédia Windows pour créer un timer haute résolution avec
Mais le timeSetEvent()
recommande l'utilisation de :
Comment puis-je utiliser CreateTimerQueueTimer() pour exécuter une méthode toutes les 10 millisecondes en C# ?
J'ai utilisé une dll multimédia Windows pour créer un timer haute résolution avec
Mais le timeSetEvent()
recommande l'utilisation de :
Comment puis-je utiliser CreateTimerQueueTimer() pour exécuter une méthode toutes les 10 millisecondes en C# ?
Voici un lien vers un wrapper C# pour CreateTimerQueueTimer
:
(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.
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.
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 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.