mirror of
https://github.com/craigerl/aprsd.git
synced 2026-03-31 12:15:34 -04:00
feat(threads): add join_non_daemon() to APRSDThreadList
Allows graceful shutdown by waiting for non-daemon threads to complete while allowing daemon threads to be terminated immediately.
This commit is contained in:
parent
b7a37322e1
commit
43ba69e352
@ -184,3 +184,15 @@ class APRSDThreadList:
|
||||
@wrapt.synchronized(lock)
|
||||
def __len__(self):
|
||||
return len(self.threads_list)
|
||||
|
||||
@wrapt.synchronized(lock)
|
||||
def join_non_daemon(self, timeout: float = 5.0):
|
||||
"""Wait for non-daemon threads to complete gracefully.
|
||||
|
||||
Args:
|
||||
timeout: Maximum seconds to wait per thread.
|
||||
"""
|
||||
for th in self.threads_list:
|
||||
if not th.daemon and th.is_alive():
|
||||
LOG.info(f'Waiting for non-daemon thread {th.name} to finish')
|
||||
th.join(timeout=timeout)
|
||||
|
||||
@ -404,3 +404,51 @@ class TestAPRSDThreadList(unittest.TestCase):
|
||||
|
||||
# Should handle concurrent access without errors
|
||||
self.assertGreaterEqual(len(thread_list), 0)
|
||||
|
||||
def test_join_non_daemon(self):
|
||||
"""Test join_non_daemon() waits for non-daemon threads."""
|
||||
|
||||
class NonDaemonTestThread(APRSDThread):
|
||||
daemon = False
|
||||
|
||||
def __init__(self, name):
|
||||
super().__init__(name)
|
||||
self.finished = False
|
||||
|
||||
def loop(self):
|
||||
time.sleep(0.2)
|
||||
self.finished = True
|
||||
return False
|
||||
|
||||
thread_list = APRSDThreadList()
|
||||
thread = NonDaemonTestThread('NonDaemonJoinTest')
|
||||
thread_list.add(thread)
|
||||
thread.start()
|
||||
|
||||
# Stop triggers the event, thread should finish its loop then exit
|
||||
thread.stop()
|
||||
thread_list.join_non_daemon(timeout=5.0)
|
||||
|
||||
self.assertTrue(thread.finished or not thread.is_alive())
|
||||
|
||||
def test_join_non_daemon_skips_daemon_threads(self):
|
||||
"""Test join_non_daemon() does not wait for daemon threads."""
|
||||
thread_list = APRSDThreadList()
|
||||
# Clear existing threads
|
||||
thread_list.threads_list = []
|
||||
|
||||
# Create a daemon thread that loops forever
|
||||
thread = TestThread('DaemonSkipTest', should_loop=True)
|
||||
thread_list.add(thread)
|
||||
thread.start()
|
||||
|
||||
# This should return quickly since it's a daemon thread
|
||||
start = time.time()
|
||||
thread_list.join_non_daemon(timeout=0.1)
|
||||
elapsed = time.time() - start
|
||||
|
||||
self.assertLess(elapsed, 0.5) # Should not wait for daemon
|
||||
|
||||
# Cleanup
|
||||
thread.stop()
|
||||
thread.join(timeout=1)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user