MicroTimer.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. using System;
  2. namespace SKMC.Api.Common.Datetime
  3. {
  4. /// <summary>
  5. /// MicroStopwatch class
  6. /// </summary>
  7. public class MicroStopwatch : System.Diagnostics.Stopwatch
  8. {
  9. readonly double _microSecPerTick =
  10. 1000000D / System.Diagnostics.Stopwatch.Frequency;
  11. public MicroStopwatch()
  12. {
  13. if (!System.Diagnostics.Stopwatch.IsHighResolution)
  14. {
  15. throw new Exception("On this system the high-resolution " +
  16. "performance counter is not available");
  17. }
  18. }
  19. public long ElapsedMicroseconds
  20. {
  21. get
  22. {
  23. return (long)(ElapsedTicks * _microSecPerTick);
  24. }
  25. }
  26. }
  27. /// <summary>
  28. /// MicroTimer class
  29. /// </summary>
  30. public class MicroTimer
  31. {
  32. public delegate void MicroTimerElapsedEventHandler(
  33. object sender,
  34. MicroTimerEventArgs timerEventArgs);
  35. public event MicroTimerElapsedEventHandler MicroTimerElapsed;
  36. System.Threading.Thread _threadTimer = null;
  37. long _ignoreEventIfLateBy = long.MaxValue;
  38. long _timerIntervalInMicroSec = 0;
  39. bool _stopTimer = true;
  40. public MicroTimer()
  41. {
  42. }
  43. public MicroTimer(long timerIntervalInMicroseconds)
  44. {
  45. Interval = timerIntervalInMicroseconds;
  46. }
  47. public long Interval
  48. {
  49. get
  50. {
  51. return System.Threading.Interlocked.Read(
  52. ref _timerIntervalInMicroSec);
  53. }
  54. set
  55. {
  56. System.Threading.Interlocked.Exchange(
  57. ref _timerIntervalInMicroSec, value);
  58. }
  59. }
  60. public long IgnoreEventIfLateBy
  61. {
  62. get
  63. {
  64. return System.Threading.Interlocked.Read(
  65. ref _ignoreEventIfLateBy);
  66. }
  67. set
  68. {
  69. System.Threading.Interlocked.Exchange(
  70. ref _ignoreEventIfLateBy, value <= 0 ? long.MaxValue : value);
  71. }
  72. }
  73. public bool Enabled
  74. {
  75. set
  76. {
  77. if (value)
  78. {
  79. Start();
  80. }
  81. else
  82. {
  83. Stop();
  84. }
  85. }
  86. get
  87. {
  88. return (_threadTimer != null && _threadTimer.IsAlive);
  89. }
  90. }
  91. public void Start()
  92. {
  93. if (Enabled || Interval <= 0)
  94. {
  95. return;
  96. }
  97. _stopTimer = false;
  98. System.Threading.ThreadStart threadStart = delegate()
  99. {
  100. NotificationTimer(ref _timerIntervalInMicroSec,
  101. ref _ignoreEventIfLateBy,
  102. ref _stopTimer);
  103. };
  104. _threadTimer = new System.Threading.Thread(threadStart);
  105. _threadTimer.Priority = System.Threading.ThreadPriority.Highest;
  106. _threadTimer.Start();
  107. }
  108. public void Stop()
  109. {
  110. _stopTimer = true;
  111. }
  112. public void StopAndWait()
  113. {
  114. StopAndWait(System.Threading.Timeout.Infinite);
  115. }
  116. public bool StopAndWait(int timeoutInMilliSec)
  117. {
  118. _stopTimer = true;
  119. if (!Enabled || _threadTimer.ManagedThreadId ==
  120. System.Threading.Thread.CurrentThread.ManagedThreadId)
  121. {
  122. return true;
  123. }
  124. return _threadTimer.Join(timeoutInMilliSec);
  125. }
  126. public void Abort()
  127. {
  128. _stopTimer = true;
  129. if (Enabled)
  130. {
  131. _threadTimer.Abort();
  132. }
  133. }
  134. void NotificationTimer(ref long timerIntervalInMicroSec,
  135. ref long ignoreEventIfLateBy,
  136. ref bool stopTimer)
  137. {
  138. int timerCount = 0;
  139. long nextNotification = 0;
  140. MicroStopwatch microStopwatch = new MicroStopwatch();
  141. microStopwatch.Start();
  142. while (!stopTimer)
  143. {
  144. long callbackFunctionExecutionTime =
  145. microStopwatch.ElapsedMicroseconds - nextNotification;
  146. long timerIntervalInMicroSecCurrent =
  147. System.Threading.Interlocked.Read(ref timerIntervalInMicroSec);
  148. long ignoreEventIfLateByCurrent =
  149. System.Threading.Interlocked.Read(ref ignoreEventIfLateBy);
  150. nextNotification += timerIntervalInMicroSecCurrent;
  151. timerCount++;
  152. long elapsedMicroseconds = 0;
  153. while ( (elapsedMicroseconds = microStopwatch.ElapsedMicroseconds)
  154. < nextNotification)
  155. {
  156. System.Threading.Thread.SpinWait(10);
  157. }
  158. long timerLateBy = elapsedMicroseconds - nextNotification;
  159. if (timerLateBy >= ignoreEventIfLateByCurrent)
  160. {
  161. continue;
  162. }
  163. MicroTimerEventArgs microTimerEventArgs =
  164. new MicroTimerEventArgs(timerCount,
  165. elapsedMicroseconds,
  166. timerLateBy,
  167. callbackFunctionExecutionTime);
  168. MicroTimerElapsed(this, microTimerEventArgs);
  169. }
  170. microStopwatch.Stop();
  171. }
  172. }
  173. /// <summary>
  174. /// MicroTimer Event Argument class
  175. /// </summary>
  176. public class MicroTimerEventArgs : EventArgs
  177. {
  178. // Simple counter, number times timed event (callback function) executed
  179. public int TimerCount { get; private set; }
  180. // Time when timed event was called since timer started
  181. public long ElapsedMicroseconds { get; private set; }
  182. // How late the timer was compared to when it should have been called
  183. public long TimerLateBy { get; private set; }
  184. // Time it took to execute previous call to callback function (OnTimedEvent)
  185. public long CallbackFunctionExecutionTime { get; private set; }
  186. public MicroTimerEventArgs(int timerCount,
  187. long elapsedMicroseconds,
  188. long timerLateBy,
  189. long callbackFunctionExecutionTime)
  190. {
  191. TimerCount = timerCount;
  192. ElapsedMicroseconds = elapsedMicroseconds;
  193. TimerLateBy = timerLateBy;
  194. CallbackFunctionExecutionTime = callbackFunctionExecutionTime;
  195. }
  196. }
  197. }