Advertisement
Guest User

Untitled

a guest
Aug 22nd, 2017
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.85 KB | None | 0 0
  1. //When sending out a message
  2. timeoutManager.Add("Message001")
  3.  
  4. //When receiving a reply
  5. bool replyWasExpected = timeoutManager.MarkOldestItemAsFinished(x=>x=="Message001");
  6.  
  7. //When no reply is received
  8. timeoutManager.OnTimout += (evt, args) =>{Console.WriteLine("HELP!");};
  9.  
  10. using System;
  11. using System.Collections.Concurrent;
  12. using System.Collections.Generic;
  13. using System.Linq;
  14. using System.Text;
  15. using System.Threading;
  16. using System.Threading.Tasks;
  17.  
  18. namespace McatXml
  19. {
  20.  
  21. public class TimeoutManager<T_Item>
  22. {
  23. private readonly TimeSpan timeout = TimeSpan.FromSeconds(30);
  24.  
  25. private BlockingCollection<ItemWithTimeout> itemsWaitingForTimeout = new BlockingCollection<ItemWithTimeout>();
  26.  
  27. public class TimeoutEventArgs : EventArgs
  28. {
  29. public T_Item Item { get; private set; }
  30. public TimeoutEventArgs(T_Item item) { this.Item = item; }
  31. }
  32. /// <summary> called whenever an item is not finished before the timeout </summary>
  33. public event EventHandler<TimeoutEventArgs> OnTimeout;
  34.  
  35. /// <summary> private wrapper class to decorate an item with a timeout </summary>
  36. private class ItemWithTimeout
  37. {
  38. internal readonly T_Item Item;
  39. internal readonly Stopwatch Watch;
  40. internal volatile bool FinishedWaiting;
  41. internal ItemWithTimeout(T_Item item)
  42. {
  43. this.Item = item;
  44. this.Watch = Stopwatch.StartNew();
  45. this.FinishedWaiting = false;
  46. }
  47. }
  48.  
  49. public TimeoutManager(TimeSpan timeout)
  50. {
  51. this.timeout = timeout;
  52. OnTimeout += (sender, args) => { };
  53. Task loop = new Task(this.timeoutLoop, TaskCreationOptions.LongRunning);
  54. loop.Start();
  55. }
  56.  
  57. public void Add(T_Item item)
  58. {
  59. var itemExt = new ItemWithTimeout(item);
  60. itemsWaitingForTimeout.Add(itemExt);
  61. itemsWaitingForTimeout.Add(itemExt); // this is an ugly hack!
  62. }
  63.  
  64. /// <summary> mark all items as finished, that fit the given condition </summary>
  65. public bool MarkAllAsFinished(Func<T_Item, bool> isMatch = null)
  66. {
  67. return markAsFinished(stopAfterFirstHit: false, reverseOrder: false, isMatch: isMatch);
  68. }
  69. /// <summary> mark the most recent item as finished, that fits the given condition </summary>
  70. public bool MarkNewestAsFinished(Func<T_Item, bool> isMatch = null)
  71. {
  72. return markAsFinished(stopAfterFirstHit: true, reverseOrder: true, isMatch: isMatch);
  73. }
  74. /// <summary> mark the oldest item as finished, that fits the given condition </summary>
  75. public bool MarkOldestAsFinished(Func<T_Item, bool> isMatch = null)
  76. {
  77. return markAsFinished(stopAfterFirstHit: true, reverseOrder: false, isMatch: isMatch);
  78. }
  79.  
  80. /// <summary> mark items as finished, that fit the given condition </summary>
  81. private bool markAsFinished(bool stopAfterFirstHit, bool reverseOrder, Func<T_Item, bool> isMatch = null)
  82. {
  83. var items = this.itemsWaitingForTimeout.ToArray();
  84. bool success = false;
  85. int startIdx = reverseOrder ? items.Length - 1 : 0;
  86. int inc = reverseOrder ? -1 : 1;
  87. for (int i = startIdx; i < items.Length && i >= 0; i += inc)
  88. {
  89. var item = items[i];
  90. if (item.FinishedWaiting) continue;
  91. if (isMatch == null || isMatch(item.Item))
  92. {
  93. lock (item)
  94. {
  95. if (item.FinishedWaiting) continue;
  96. item.FinishedWaiting = true;
  97. }
  98. success = true;
  99. if (stopAfterFirstHit) break;
  100. }
  101. }
  102. return success;
  103. }
  104.  
  105. /// <summary> for all items that are not finished, check whether their time is up </summary>
  106. private void timeoutLoop()
  107. {
  108. foreach (var item in itemsWaitingForTimeout.GetConsumingEnumerable())
  109. {
  110. if (item.FinishedWaiting) continue; // item has already been finished
  111.  
  112. while (!item.FinishedWaiting && item.Watch.Elapsed < this.timeout)
  113. {
  114. // wait until the timeout has passed or the item is finished
  115. Thread.Sleep(
  116. TimeSpan.FromMilliseconds(Math.Max(1,
  117. this.timeout.TotalMilliseconds -
  118. item.Watch.ElapsedMilliseconds)));
  119. }
  120.  
  121. if (item.FinishedWaiting) continue; // item has been finished while we were waiting
  122. lock (item)
  123. {
  124. if (item.FinishedWaiting) continue; // item has been finished while we ackquired the lock
  125.  
  126. item.FinishedWaiting = true;
  127. }
  128. // item has not been finished in time!
  129. OnTimeout(this, new TimeoutEventArgs(item.Item));
  130. }
  131. }
  132. }
  133. static class Program
  134. {
  135. static void Main()
  136. {
  137.  
  138. TimeoutManager<int> test = new TimeoutManager<int>(TimeSpan.FromSeconds(5));
  139. test.OnTimeout += (sender, args) => { Console.WriteLine("Timeout: {0}", args.Item); };
  140.  
  141. Parallel.ForEach(Enumerable.Range(0, 100).OrderBy(i => Guid.NewGuid()), (i) =>
  142. {
  143. test.Add(i);
  144. });
  145.  
  146. Parallel.ForEach(Enumerable.Range(0 , 90).OrderBy(i => Guid.NewGuid()), (i) =>
  147. {
  148. if (!test.MarkAllAsFinished(x => x == i))
  149. Console.WriteLine("could not mark as finished: {0}", i);
  150. });
  151.  
  152. Console.ReadLine();
  153.  
  154.  
  155.  
  156. }
  157. }
  158. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement