Guest User

Untitled

a guest
Apr 22nd, 2018
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.46 KB | None | 0 0
  1. using System;
  2. using System.Threading;
  3.  
  4. namespace GraniteStateHacker.Utilities.Uwp.Concurrency
  5. {
  6. /// <summary>
  7. /// Use an instance of this class to guard a resource with enforced timeouts and safer syntax
  8. /// than ReaderWriterLockSlim provides on its own.
  9. ///
  10. /// Unlike the lock ([object]) {} mechanism, this class provides an exclusive and non exclusive guard.
  11. /// To make it easier to use, this class wraps System.Threading.ReaderWriterLockSlim
  12. /// in an IDisposable, making it easier to ensure locks are cleared correctly. Simply wrap your guarded coded with
  13. /// using (myLockInstance.NotExclusive()) { //guarded code goes here } for scoped activities that
  14. /// can run concurrently with other NonExclusive scopes, and using (myLockInstance.Exclusive) { } for
  15. /// code that must operate on the resource exclusively.
  16. ///
  17. /// There's room for improvements here, like making the timout configurable in a config file, but otherwise
  18. /// it's a reasonable start for a utility.
  19. ///
  20. /// Understand that while Lock is an IDisposable itself, it's only cleaning up the underlying
  21. /// ReaderWriterLockSlim. It's intended to be used to guard a specific resource for the lifetime of
  22. /// that resource, even if that resource's lifetime isn't scoped.
  23. ///
  24. /// </summary>
  25. /// <example>
  26. /// var myLock = new Lock();
  27. ///
  28. /// MyTableData GetData(string tablename)
  29. /// {
  30. /// using (myLock.NotExclusive())
  31. /// {
  32. /// return db.ReadTable(tablename);
  33. /// }
  34. /// }
  35. /// </example>
  36. /// <example>
  37. /// void SetData(string tablename, MyTableData content)
  38. /// {
  39. /// using(myLock.Exclusive(Timespan.FromSeconds(3)) // Allow three seconds to acquire lock
  40. /// {
  41. /// db.UpdateTable(tablename, content);
  42. /// }
  43. /// }
  44. /// </example>
  45. /// <example>
  46. /// void ConditionallyUpdateData(string tablename, MyTableData content)
  47. /// {
  48. /// using(myLock.UpgradeableLock())
  49. /// {
  50. /// var isWriteNeeded = db.ReadTable(tablename);
  51. /// if(isWriteNeeded)
  52. /// {
  53. /// using(myLock.Exclusive())
  54. /// {
  55. /// db.UpdateTable(tablename, content);
  56. /// }
  57. /// }
  58. /// }
  59. /// }
  60. /// </example>
  61. public class Lock : IDisposable
  62. {
  63. ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
  64. TimeSpan defaultTimeout = TimeSpan.FromSeconds(2); //allow two seconds to acquire lock before throwing exception.
  65.  
  66. public IDisposable NotExclusive()
  67. {
  68. return NotExclusive(defaultTimeout);
  69. }
  70.  
  71. public IDisposable NotExclusive(TimeSpan timeout)
  72. {
  73. if (!_lock.TryEnterReadLock(timeout))
  74. throw new SynchronizationLockException($"Failed to acquire non-exclusive lock within the given timeout. ({timeout.TotalMilliseconds}ms).");
  75. return new LockInternal(_lock.ExitReadLock);
  76. }
  77.  
  78. public IDisposable Exclusive()
  79. {
  80. return Exclusive(defaultTimeout);
  81. }
  82.  
  83. public IDisposable Exclusive(TimeSpan timeout)
  84. {
  85. if (!_lock.TryEnterWriteLock(timeout))
  86. throw new SynchronizationLockException($"Failed to acquire exclusive lock within the given timeout. ({timeout.TotalMilliseconds}ms).");
  87. return new LockInternal(_lock.ExitWriteLock);
  88. }
  89.  
  90. public IDisposable UpgradeableToExclusive()
  91. {
  92. return UpgradeableToExclusive(defaultTimeout);
  93. }
  94.  
  95. public IDisposable UpgradeableToExclusive(TimeSpan timeout)
  96. {
  97. if (!_lock.TryEnterUpgradeableReadLock(timeout))
  98. throw new SynchronizationLockException($"Failed acquire upgradeable non-exclusive lock within the given timeout. ({timeout.TotalMilliseconds}ms).");
  99. return new LockInternal(_lock.ExitUpgradeableReadLock);
  100. }
  101.  
  102. public void Dispose()
  103. {
  104. try
  105. {
  106. _lock.Dispose();
  107. }
  108. catch (Exception) { }
  109. }
  110.  
  111. private class LockInternal : IDisposable
  112. {
  113. Action _lockRelease;
  114.  
  115. public LockInternal(Action lockRelease)
  116. {
  117. _lockRelease = lockRelease;
  118. }
  119.  
  120. public void Dispose()
  121. {
  122. _lockRelease();
  123. }
  124. }
  125. }
  126. }
Add Comment
Please, Sign In to add comment