CurrentThreadScheduler.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // this code is borrowed from RxOfficial(rx.codeplex.com) and modified
  2. // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
  3. using System.ComponentModel;
  4. using System.Threading;
  5. using UniRx.InternalUtil;
  6. using UniRx;
  7. using System;
  8. using System.Diagnostics;
  9. using System.Collections.Generic;
  10. namespace UniRx
  11. {
  12. public static partial class Scheduler
  13. {
  14. public static readonly IScheduler CurrentThread = new CurrentThreadScheduler();
  15. public static bool IsCurrentThreadSchedulerScheduleRequired { get { return CurrentThreadScheduler.IsScheduleRequired; } }
  16. /// <summary>
  17. /// Represents an object that schedules units of work on the current thread.
  18. /// </summary>
  19. /// <seealso cref="Scheduler.CurrentThread">Singleton instance of this type exposed through this static property.</seealso>
  20. class CurrentThreadScheduler : IScheduler
  21. {
  22. [ThreadStatic]
  23. static SchedulerQueue s_threadLocalQueue;
  24. [ThreadStatic]
  25. static Stopwatch s_clock;
  26. private static SchedulerQueue GetQueue()
  27. {
  28. return s_threadLocalQueue;
  29. }
  30. private static void SetQueue(SchedulerQueue newQueue)
  31. {
  32. s_threadLocalQueue = newQueue;
  33. }
  34. private static TimeSpan Time
  35. {
  36. get
  37. {
  38. if (s_clock == null)
  39. s_clock = Stopwatch.StartNew();
  40. return s_clock.Elapsed;
  41. }
  42. }
  43. /// <summary>
  44. /// Gets a value that indicates whether the caller must call a Schedule method.
  45. /// </summary>
  46. [EditorBrowsable(EditorBrowsableState.Advanced)]
  47. public static bool IsScheduleRequired
  48. {
  49. get
  50. {
  51. return GetQueue() == null;
  52. }
  53. }
  54. public IDisposable Schedule(Action action)
  55. {
  56. return Schedule(TimeSpan.Zero, action);
  57. }
  58. public IDisposable Schedule(TimeSpan dueTime, Action action)
  59. {
  60. if (action == null)
  61. throw new ArgumentNullException("action");
  62. var dt = Time + Scheduler.Normalize(dueTime);
  63. var si = new ScheduledItem(action, dt);
  64. var queue = GetQueue();
  65. if (queue == null)
  66. {
  67. queue = new SchedulerQueue(4);
  68. queue.Enqueue(si);
  69. CurrentThreadScheduler.SetQueue(queue);
  70. try
  71. {
  72. Trampoline.Run(queue);
  73. }
  74. finally
  75. {
  76. CurrentThreadScheduler.SetQueue(null);
  77. }
  78. }
  79. else
  80. {
  81. queue.Enqueue(si);
  82. }
  83. return si.Cancellation;
  84. }
  85. static class Trampoline
  86. {
  87. public static void Run(SchedulerQueue queue)
  88. {
  89. while (queue.Count > 0)
  90. {
  91. var item = queue.Dequeue();
  92. if (!item.IsCanceled)
  93. {
  94. var wait = item.DueTime - CurrentThreadScheduler.Time;
  95. if (wait.Ticks > 0)
  96. {
  97. Thread.Sleep(wait);
  98. }
  99. if (!item.IsCanceled)
  100. item.Invoke();
  101. }
  102. }
  103. }
  104. }
  105. public DateTimeOffset Now
  106. {
  107. get { return Scheduler.Now; }
  108. }
  109. }
  110. }
  111. }