1+ import atexit
12import os
23import sys
34import threading
45from multiprocessing import Manager
56from pathlib import Path
67
8+ # noinspection PyPep8Naming
79from geophires_x import GEOPHIRESv3 as geophires
810
9- # Assuming these are in a sibling file or accessible path
1011from .common import _get_logger
1112from .geophires_input_parameters import GeophiresInputParameters
1213from .geophires_input_parameters import ImmutableGeophiresInputParameters
1617class GeophiresXClient :
1718 """
1819 A thread-safe and process-safe client for running GEOPHIRES simulations.
19- Relies on an explicit shutdown() call to clean up background processes.
20+ It automatically manages a background process via atexit and provides an
21+ explicit shutdown() method for advanced use cases like testing.
2022 """
2123
2224 # --- Class-level shared resources ---
2325 _manager = None
2426 _cache = None
2527 _lock = None
2628
27- # A standard threading lock to make the one-time initialization thread-safe.
2829 _init_lock = threading .Lock ()
30+ """A standard threading lock to make the one-time initialization thread-safe."""
2931
3032 def __init__ (self , enable_caching = True , logger_name = None ):
3133 if logger_name is None :
@@ -41,25 +43,31 @@ def __init__(self, enable_caching=True, logger_name=None):
4143 @classmethod
4244 def _initialize_shared_resources (cls ):
4345 """
44- Initializes the multiprocessing Manager and shared resources (cache, lock)
45- in a thread-safe and process-safe manner.
46+ Initializes the multiprocessing Manager and shared resources in a
47+ thread-safe manner. It also registers the shutdown hook to ensure
48+ automatic cleanup on application exit.
4649 """
4750 with cls ._init_lock :
4851 if cls ._manager is None :
4952 cls ._manager = Manager ()
5053 cls ._cache = cls ._manager .dict ()
5154 cls ._lock = cls ._manager .RLock ()
55+ # Register the shutdown method to be called automatically on exit.
56+ atexit .register (cls .shutdown )
5257
5358 @classmethod
5459 def shutdown (cls ):
5560 """
56- Explicitly shuts down the background manager process.
57- This MUST be called when the application is finished with the client
58- to prevent orphaned processes.
61+ Explicitly shuts down the background manager process and de-registers
62+ the atexit hook to prevent errors if called multiple times.
63+ This is useful for test suites or applications that need to precisely
64+ control the resource lifecycle.
5965 """
6066 with cls ._init_lock :
6167 if cls ._manager is not None :
6268 cls ._manager .shutdown ()
69+ # De-register the hook to avoid trying to shut down twice.
70+ atexit .unregister (cls .shutdown )
6371 cls ._manager = None
6472 cls ._cache = None
6573 cls ._lock = None
0 commit comments