IAsyncGate.cs 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Reactive.Linq;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace System.Reactive.Threading
  8. {
  9. /// <summary>
  10. /// Synchronization primitive that provides <see cref="System.Threading.Monitor"/>-style
  11. /// exclusive access semantics, but with an asynchronous API.
  12. /// </summary>
  13. /// <remarks>
  14. /// <para>
  15. /// This enables <see cref="AsyncObservable.Synchronize{TSource}(IAsyncObservable{TSource}, IAsyncGate)"/>
  16. /// and <see cref="AsyncObserver.Synchronize{TSource}(IAsyncObserver{TSource}, IAsyncGate)"/>
  17. /// to be used to synchronize access to an observer with a custom synchronization primitive.
  18. /// </para>
  19. /// <para>
  20. /// These methods model the equivalents for <see cref="IObservable{T}"/> and <see cref="IObserver{T}"/>
  21. /// in <c>System.Reactive</c>. Those offer overloads accepting a 'gate' parameter, and if you pass
  22. /// the same object to multiple calls to these methods, they will all synchronize their operation
  23. /// through that same gate object. The <c>gate</c> parameter in those methods is of type
  24. /// <see cref="System.Object"/>, which works because all .NET objects have an associated monitor.
  25. /// (It's created on demand when you first use <c>lock</c> or something equivalent.)
  26. /// </para>
  27. /// <para>
  28. /// That approach is problematic in an async world, because this built-in monitor blocks the
  29. /// calling thread when contention occurs. The basic idea of AsyncRx.NET is to avoid such
  30. /// blocking. It can't always be avoided, and in cases where we can be certain that lock
  31. /// acquisition times will be short, the conventional .NET monitor is still a good choice.
  32. /// But since these <c>Synchronize</c> operators allow the caller to pass a gate which the
  33. /// application code itself might lock, we have no control over how long the lock might be
  34. /// held. So it would be inappropriate to use a monitor here.
  35. /// </para>
  36. /// <para>
  37. /// Since the .NET runtime does not currently offer any asynchronous direct equivalent to
  38. /// monitor, this interface defines the required API. The <see cref="AsyncGate"/> class
  39. /// provide a basic implementation. If applications require additional features, (e.g.
  40. /// if they want cancellation support when the application tries to acquire the lock)
  41. /// they can provide their own implementation.
  42. /// </para>
  43. /// </remarks>
  44. public interface IAsyncGate
  45. {
  46. /// <summary>
  47. /// Acquires the lock.
  48. /// </summary>
  49. /// <returns>
  50. /// A task that completes when the lock has been acquired, returning an <see cref="AsyncGateReleaser"/>
  51. /// which can be disposed to release the lock.
  52. /// </returns>
  53. /// <remarks>
  54. /// <para>
  55. /// Applications release the lock by disposing the <see cref="AsyncGateReleaser"/> returned by this
  56. /// method. Typically this is done with a <c>using</c> statement or declaration.
  57. /// </para>
  58. /// </remarks>
  59. public ValueTask<AsyncGateReleaser> LockAsync();
  60. /// <summary>
  61. /// Releases the lock. Applications typically won't call this directly, and will use
  62. /// the <see cref="AsyncGateReleaser"/> returned by <see cref="LockAsync"/> instead.
  63. /// </summary>
  64. /// <remarks>
  65. /// This method needs to be publicly accessible so that a single <see cref="AsyncGateReleaser"/>
  66. /// can be shared by all implementations of this interface.
  67. /// </remarks>
  68. public void Release();
  69. }
  70. }