123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657 |
- from sccd.realtime.time import *
- from sccd.controller.controller import *
- from sccd.util.duration import *
- import threading
- # Thread-safe real-time Controller execution in a thread
- class ThreadsPlatform:
- def __init__(self, controller: Controller):
- self.controller = controller
- self.timer = Timer(impl=DefaultTimeImplementation, unit=self.controller.cd.get_delta())
- self.lock = threading.Lock() # A queue would also work, but because of Python's GIL, a queue would not perform better.
- self.condition = threading.Condition()
- # keep simulation responsive even if computer cannot keep up
- self.purposefully_behind = 0
- def create_controller_thread(self) -> threading.Thread:
- def thread():
- # condition object expects fractions of seconds
- to_condition_wait_time = get_conversion_f_float(self.controller.cd.get_delta(), duration(1, Second))
- # simulation starts "now" (wall-clock time)
- self.timer.start()
- while True:
- with self.lock:
- self.controller.run_until(self.timer.now() + self.purposefully_behind) # may take a while
- next_wakeup = self.controller.next_wakeup()
- if next_wakeup is not None:
- sleep_duration = next_wakeup - self.timer.now()
- if sleep_duration < 0:
- self.purposefully_behind = sleep_duration
- sleep_duration = 0
- else:
- self.purposefully_behind = 0
- with self.condition:
- self.condition.wait(to_condition_wait_time(sleep_duration))
- else:
- with self.condition:
- self.condition.wait()
- return threading.Thread(target=thread)
- def now(self):
- return self.timer.now() + self.purposefully_behind
- # Add an input event with timestamp "now" (wall-clock time)
- # Safe to call this method from any thread.
- def add_input_now(self, port, event_name, params=[]):
- with self.lock:
- self.controller.add_input(timestamp=self.timer.now(), port=port, event_name=event_name, params=params)
- with self.condition:
- self.condition.notify() # wake up controller thread if sleeping
|