Skip to content

Commit 73ff931

Browse files
The simulation app now waits for the thread manager to be done before closing. This avoids a massive mess with threads.
1 parent 797d5e2 commit 73ff931

File tree

6 files changed

+93
-7
lines changed

6 files changed

+93
-7
lines changed

src/environments/large_scale_lunar.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ def update(self) -> None:
131131
def monitor_thread_is_alive(self) -> None:
132132
return self.LSTM.map_manager.hr_dem_gen.monitor_thread.thread.is_alive()
133133

134+
def get_wait_for_threads(self) -> None:
135+
return [self.LSTM.map_manager.hr_dem_gen.monitor_thread.thread.join]
136+
134137
def load(self) -> None:
135138
"""
136139
Loads the lab interactive elements in the stage.

src/environments_wrappers/__init__.py

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,86 @@
99

1010
def startSim(cfg: dict):
1111
from omni.isaac.kit import SimulationApp
12+
import omni
1213
from src.environments.rendering import set_lens_flares, set_chromatic_aberrations, set_motion_blur
1314

15+
class SimulationApp_wait(SimulationApp):
16+
def __init__(self, launch_config: dict = None, experience: str = "") -> None:
17+
super().__init__(launch_config, experience)
18+
self.wait_for_threads = []
19+
20+
def add_wait(self, waiting_functions: list) -> None:
21+
"""
22+
Adds a list of functions that will wait until a condition is met before closing the simulation.
23+
"""
24+
self.wait_for_threads += waiting_functions
25+
26+
def close(self, wait_for_replicator=True) -> None:
27+
"""Close the running Omniverse Toolkit."""
28+
try:
29+
# make sure that any replicator workflows finish rendering/writing
30+
import omni.replicator.core as rep
31+
32+
if rep.orchestrator.get_status() not in [
33+
rep.orchestrator.Status.STOPPED,
34+
rep.orchestrator.Status.STOPPING,
35+
]:
36+
rep.orchestrator.stop()
37+
if wait_for_replicator:
38+
rep.orchestrator.wait_until_complete()
39+
40+
# Disable capture on play to avoid replicator engaging on any new timeline events
41+
rep.orchestrator.set_capture_on_play(False)
42+
except Exception:
43+
pass
44+
45+
for wait in self.wait_for_threads:
46+
self._app.print_and_log(f"Waiting for external thread to join: {wait}")
47+
wait()
48+
49+
# workaround for exit issues, clean the stage first:
50+
if omni.usd.get_context().can_close_stage():
51+
omni.usd.get_context().close_stage()
52+
# omni.kit.app.get_app().update()
53+
# check if exited already
54+
if not self._exiting:
55+
self._exiting = True
56+
self._app.print_and_log("Simulation App Shutting Down")
57+
58+
# We are exisitng but something is still loading, wait for it to load to avoid a deadlock
59+
def is_stage_loading() -> bool:
60+
"""Convenience function to see if any files are being loaded.
61+
bool: Convenience function to see if any files are being loaded. True if loading, False otherwise
62+
"""
63+
import omni.usd
64+
65+
context = omni.usd.get_context()
66+
if context is None:
67+
return False
68+
else:
69+
_, _, loading = context.get_stage_loading_status()
70+
return loading > 0
71+
72+
if is_stage_loading():
73+
print(
74+
" Waiting for USD resource operations to complete (this may take a few seconds), use Ctrl-C to exit immediately"
75+
)
76+
while is_stage_loading():
77+
self._app.update()
78+
79+
self._app.shutdown()
80+
# disabled on linux to workaround issues where unloading plugins causes carb to fail
81+
self._framework.unload_all_plugins()
82+
# Force all omni module to unload on close
83+
# This prevents crash on exit
84+
# for m in list(sys.modules.keys()):
85+
# if "omni" in m and m != "omni.kit.app":
86+
# del sys.modules[m]
87+
print("Simulation App Shutdown Complete")
88+
1489
# Starts the simulation and allows to import things related to Isaac and PXR
1590
renderer_cfg = cfg["rendering"]["renderer"]
16-
simulation_app = SimulationApp(renderer_cfg.__dict__)
91+
simulation_app = SimulationApp_wait(renderer_cfg.__dict__)
1792
set_lens_flares(cfg)
1893
set_motion_blur(cfg)
1994
set_chromatic_aberrations(cfg)

src/environments_wrappers/ros2/base_wrapper_ros2.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,10 @@ def monitor_thread_is_alive(self):
217217
"""
218218

219219
return True
220+
221+
def get_wait_for_threads(self):
222+
"""
223+
Returns the list of waiting threads.
224+
"""
225+
226+
return []

src/environments_wrappers/ros2/largescale_ros2.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,6 @@ def set_sun_pose(self, data: Pose) -> None:
124124

125125
def monitor_thread_is_alive(self):
126126
return self.LC.monitor_thread_is_alive()
127+
128+
def get_wait_for_threads(self):
129+
return self.LC.get_wait_for_threads()

src/environments_wrappers/ros2/simulation_manager_ros2.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ def __init__(
179179
self.exec2_thread = Thread(target=self.exec2.spin, daemon=True, args=())
180180
self.exec2_thread.start()
181181

182+
if self.ROSLabManager.get_wait_for_threads():
183+
self.simulation_app.add_wait(self.ROSLabManager.get_wait_for_threads())
184+
182185
# Have you ever asked your self: "Is there a limit of topics one can subscribe to in ROS2?"
183186
# Yes "Josh" there is.
184187
# 24 topics. More than that and you won't reveive any messages.

src/terrain_management/large_scale_terrain/high_resolution_DEM_workers.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,6 @@ def monitor_main_thread(self) -> None:
802802
- The ctrl-c signal. This was added as it seems that the simulation was completely ignoring the ctrl-c signal.
803803
"""
804804

805-
use_multiprocessing = False
806805
while not self.event.is_set():
807806
time.sleep(1)
808807
if not threading.main_thread().is_alive():
@@ -818,13 +817,9 @@ def monitor_main_thread(self) -> None:
818817
logger.warn(
819818
"Use kill -9 PID to kill the remaining threads. PID being the PIDs returned by the previous command."
820819
)
821-
use_multiprocessing = True
822820
break
823821
if self.ctrl_c:
824822
logger.debug("Ctrl-C caught, shutting down workers.")
825823
break
826-
if use_multiprocessing:
827-
self.apply_shutdowns_in_different_process()
828-
else:
829-
self.apply_shutdowns()
824+
self.apply_shutdowns()
830825
logger.debug("Thread monitor exiting.")

0 commit comments

Comments
 (0)