1
+ import atexit
1
2
import os
2
3
import sys
3
4
import threading
4
5
from multiprocessing import Manager
5
6
from pathlib import Path
6
7
8
+ # noinspection PyPep8Naming
7
9
from geophires_x import GEOPHIRESv3 as geophires
8
10
9
- # Assuming these are in a sibling file or accessible path
10
11
from .common import _get_logger
11
12
from .geophires_input_parameters import GeophiresInputParameters
12
13
from .geophires_input_parameters import ImmutableGeophiresInputParameters
16
17
class GeophiresXClient :
17
18
"""
18
19
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.
20
22
"""
21
23
22
24
# --- Class-level shared resources ---
23
25
_manager = None
24
26
_cache = None
25
27
_lock = None
26
28
27
- # A standard threading lock to make the one-time initialization thread-safe.
28
29
_init_lock = threading .Lock ()
30
+ """A standard threading lock to make the one-time initialization thread-safe."""
29
31
30
32
def __init__ (self , enable_caching = True , logger_name = None ):
31
33
if logger_name is None :
@@ -41,25 +43,31 @@ def __init__(self, enable_caching=True, logger_name=None):
41
43
@classmethod
42
44
def _initialize_shared_resources (cls ):
43
45
"""
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.
46
49
"""
47
50
with cls ._init_lock :
48
51
if cls ._manager is None :
49
52
cls ._manager = Manager ()
50
53
cls ._cache = cls ._manager .dict ()
51
54
cls ._lock = cls ._manager .RLock ()
55
+ # Register the shutdown method to be called automatically on exit.
56
+ atexit .register (cls .shutdown )
52
57
53
58
@classmethod
54
59
def shutdown (cls ):
55
60
"""
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.
59
65
"""
60
66
with cls ._init_lock :
61
67
if cls ._manager is not None :
62
68
cls ._manager .shutdown ()
69
+ # De-register the hook to avoid trying to shut down twice.
70
+ atexit .unregister (cls .shutdown )
63
71
cls ._manager = None
64
72
cls ._cache = None
65
73
cls ._lock = None
0 commit comments