SynchronizationContextScheduler.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
  2. #if !NO_SYNCCTX
  3. using System.Reactive.Disposables;
  4. using System.Threading;
  5. namespace System.Reactive.Concurrency
  6. {
  7. /// <summary>
  8. /// Represents an object that schedules units of work on a provided <seealso cref="T:System.Threading.SynchronizationContext"/>.
  9. /// </summary>
  10. public class SynchronizationContextScheduler : LocalScheduler
  11. {
  12. private readonly SynchronizationContext _context;
  13. private readonly bool _alwaysPost;
  14. /// <summary>
  15. /// Creates an object that schedules units of work on the provided <see cref="T:System.Threading.SynchronizationContext"/>.
  16. /// </summary>
  17. /// <param name="context">Synchronization context to schedule units of work on.</param>
  18. /// <exception cref="ArgumentNullException"><paramref name="context"/> is null.</exception>
  19. public SynchronizationContextScheduler(SynchronizationContext context)
  20. {
  21. if (context == null)
  22. throw new ArgumentNullException("context");
  23. _context = context;
  24. _alwaysPost = true;
  25. }
  26. /// <summary>
  27. /// Creates an object that schedules units of work on the provided <see cref="T:System.Threading.SynchronizationContext"/>.
  28. /// </summary>
  29. /// <param name="context">Synchronization context to schedule units of work on.</param>
  30. /// <param name="alwaysPost">Configures whether scheduling always posts to the synchronization context, regardless whether the caller is on the same synchronization context.</param>
  31. /// <exception cref="ArgumentNullException"><paramref name="context"/> is null.</exception>
  32. public SynchronizationContextScheduler(SynchronizationContext context, bool alwaysPost)
  33. {
  34. if (context == null)
  35. throw new ArgumentNullException("context");
  36. _context = context;
  37. _alwaysPost = alwaysPost;
  38. }
  39. /// <summary>
  40. /// Schedules an action to be executed.
  41. /// </summary>
  42. /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
  43. /// <param name="state">State passed to the action to be executed.</param>
  44. /// <param name="action">Action to be executed.</param>
  45. /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns>
  46. /// <exception cref="ArgumentNullException"><paramref name="action"/> is null.</exception>
  47. public override IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
  48. {
  49. if (action == null)
  50. throw new ArgumentNullException("action");
  51. var d = new SingleAssignmentDisposable();
  52. if (!_alwaysPost && _context == SynchronizationContext.Current)
  53. {
  54. d.Disposable = action(this, state);
  55. }
  56. else
  57. {
  58. _context.PostWithStartComplete(() =>
  59. {
  60. if (!d.IsDisposed)
  61. d.Disposable = action(this, state);
  62. });
  63. }
  64. return d;
  65. }
  66. /// <summary>
  67. /// Schedules an action to be executed after dueTime.
  68. /// </summary>
  69. /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
  70. /// <param name="state">State passed to the action to be executed.</param>
  71. /// <param name="action">Action to be executed.</param>
  72. /// <param name="dueTime">Relative time after which to execute the action.</param>
  73. /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns>
  74. /// <exception cref="ArgumentNullException"><paramref name="action"/> is null.</exception>
  75. public override IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
  76. {
  77. if (action == null)
  78. throw new ArgumentNullException("action");
  79. var dt = Scheduler.Normalize(dueTime);
  80. if (dt.Ticks == 0)
  81. return Schedule(state, action);
  82. return DefaultScheduler.Instance.Schedule(state, dt, (_, state1) => Schedule(state1, action));
  83. }
  84. }
  85. }
  86. #endif