ThreadsControllerBase.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. using System;
  2. using System.Threading;
  3. using System.Collections.Generic;
  4. namespace sccdlib
  5. {
  6. public class ThreadsControllerBase : ControllerBase
  7. {
  8. bool stop_thread = false;
  9. bool keep_running;
  10. Thread thread = null;
  11. Mutex input_mutex = new Mutex(false);
  12. Mutex stop_thread_mutex = new Mutex(false);
  13. AutoResetEvent wait_handle = new AutoResetEvent(false);
  14. DateTime last_recorded_time = DateTime.UtcNow;
  15. public ThreadsControllerBase (bool keep_running = true)
  16. : base()
  17. {
  18. this.keep_running = keep_running;
  19. this.thread = new Thread (new ThreadStart (this.run));
  20. }
  21. private void handleInput(double delta)
  22. {
  23. this.input_mutex.WaitOne(-1);
  24. this.input_queue.decreaseTime(delta);
  25. foreach(Event e in this.input_queue.popDueEvents())
  26. this.broadcast (e);
  27. this.input_mutex.ReleaseMutex();
  28. }
  29. public override void start()
  30. {
  31. this.thread.Start ();
  32. }
  33. public override void stop()
  34. {
  35. this.stop_thread_mutex.WaitOne(-1);
  36. this.stop_thread = true;
  37. this.stop_thread_mutex.ReleaseMutex ();
  38. this.wait_handle.Set();
  39. }
  40. private double getWaitTime ()
  41. {
  42. this.input_mutex.WaitOne (-1);
  43. double wait_time = Math.Min (this.object_manager.getWaitTime (), this.input_queue.getEarliestTime ());
  44. this.input_mutex.ReleaseMutex ();
  45. if (double.IsPositiveInfinity (wait_time)) {
  46. if (this.done) {
  47. this.done = false;
  48. } else {
  49. this.done = true;
  50. return 0.0;
  51. }
  52. }
  53. return wait_time;
  54. }
  55. private void handleWaiting ()
  56. {
  57. double wait_time = this.getWaitTime ();
  58. if (wait_time <= 0.0)
  59. return;
  60. if (double.IsPositiveInfinity(wait_time))
  61. {
  62. if (this.keep_running)
  63. {
  64. this.wait_handle.WaitOne(-1); //Wait until signal
  65. }
  66. else
  67. {
  68. this.stop_thread_mutex.WaitOne(-1);
  69. this.stop_thread = true;
  70. this.stop_thread_mutex.ReleaseMutex();
  71. }
  72. }
  73. else if (wait_time != 0.0)
  74. {
  75. //Calculate how much wait time is left.
  76. double actual_wait_time = (wait_time - DateTime.UtcNow.Subtract(this.last_recorded_time).TotalSeconds); //In seconds and double
  77. if (actual_wait_time > 0.0)
  78. {
  79. this.wait_handle.Reset();
  80. this.wait_handle.WaitOne((int)Math.Ceiling(actual_wait_time * 1000)); //Convert to seconds and int round up
  81. }
  82. }
  83. }
  84. private void run()
  85. {
  86. this.last_recorded_time = DateTime.UtcNow;
  87. base.start ();
  88. DateTime previous_recorded_time;
  89. double last_iteration_time = 0.0;
  90. while (true)
  91. {
  92. this.handleInput(last_iteration_time);
  93. //Compute the new state based on internal events
  94. this.object_manager.stepAll(last_iteration_time);
  95. this.handleWaiting();
  96. this.stop_thread_mutex.WaitOne (-1);
  97. if (this.stop_thread)
  98. break;
  99. this.stop_thread_mutex.ReleaseMutex ();
  100. previous_recorded_time = this.last_recorded_time;
  101. this.last_recorded_time = DateTime.UtcNow;
  102. last_iteration_time = this.last_recorded_time.Subtract(previous_recorded_time).TotalSeconds;
  103. }
  104. }
  105. public void join()
  106. {
  107. this.thread.Join ();
  108. }
  109. public override void addInput(Event input_event, double time_offset = 0.0)
  110. {
  111. this.input_mutex.WaitOne (-1);
  112. base.addInput (input_event, time_offset); //TODO Add time to offset that has already passed, so that next subtraction evens it out? Also Gameloop then!
  113. this.input_mutex.ReleaseMutex ();
  114. this.wait_handle.Set();
  115. }
  116. public override void addEventList(List<Tuple<Event,double>> event_list)
  117. {
  118. this.input_mutex.WaitOne (-1);
  119. base.addEventList (event_list);
  120. this.input_mutex.ReleaseMutex ();
  121. }
  122. protected override IOutputListener createOutputListener (string[] ports)
  123. {
  124. return new ConcurrentOutputListener(ports);
  125. }
  126. }
  127. }