1 | #include "ZydecoCommon.hpp" |
2 | #include "ThreadLooping.hpp" |
3 | #include "IUpdateable.hpp" |
4 |
|
5 |
|
6 | static Logger LOGGER("ThreadLooping"); |
7 |
|
8 |
|
9 | ThreadLooping::ThreadLooping(std::string thread_name, IUpdateable& thread_update): |
10 | m_threadName(thread_name), |
11 | m_rThreadUpdate(thread_update) |
12 | { |
13 | LOGGER.Log(Logger::TRACE, "ThreadLooping('{}', ...)", m_threadName); |
14 |
|
15 | std::atomic_init(&m_aShouldThreadTerminate, false); |
16 | std::atomic_init(&m_aIsThreadRunning, false); |
17 | } |
18 |
|
19 | ThreadLooping::~ThreadLooping() |
20 | { |
21 | LOGGER.Log(Logger::TRACE, "~ThreadLooping() for '{}'", m_threadName); |
22 | Terminate(); |
23 | WaitUntilFinished(); |
24 | } |
25 |
|
26 | void ThreadLooping::Start() |
27 | { |
28 | LOGGER.Log(Logger::TRACE, "Start() for '{}'", m_threadName); |
29 |
|
30 | if (m_aIsThreadRunning.load() == false) |
31 | { |
32 | LOGGER.Log(Logger::VERBOSE, "Start(): Spawning '{}'", m_threadName); |
33 | m_aIsThreadRunning.store(true); |
34 | m_thread = std::thread(&ThreadLooping::ThreadRunLoop, this); |
35 | } |
36 | else |
37 | { |
38 | LOGGER.Log(Logger::WARNING, "Start(): Attempt to spawn '{}' ignored (already running)", m_threadName); |
39 | } |
40 | } |
41 |
|
42 | void ThreadLooping::Terminate() |
43 | { |
44 | LOGGER.Log(Logger::TRACE, "Terminate() for '{}'", m_threadName); |
45 |
|
46 | LOGGER.Log(Logger::VERBOSE, "Terminate(): Attempting to externally terminate '{}'", m_threadName); |
47 | m_aShouldThreadTerminate.store(true); |
48 | } |
49 |
|
50 | bool ThreadLooping::IsRunning() |
51 | { |
52 | return m_aIsThreadRunning.load(); |
53 | } |
54 |
|
55 | void ThreadLooping::WaitUntilFinished() |
56 | { |
57 | LOGGER.Log(Logger::TRACE, "WaitUntilFinished() for '{}'", m_threadName); |
58 |
|
59 | if (m_thread.joinable()) |
60 | { |
61 | LOGGER.Log(Logger::VERBOSE, "WaitUntilFinished(): Waiting for end of '{}'", m_threadName); |
62 | m_thread.join(); |
63 | } |
64 | LOGGER.Log(Logger::VERBOSE, "WaitUntilFinished(): '{}' finished", m_threadName); |
65 | } |
66 |
|
67 | void ThreadLooping::ThreadRunLoop() |
68 | { |
69 | LOGGER.Log(Logger::TRACE, "ThreadRunLoop() for '{}'", m_threadName); |
70 |
|
71 | while (m_aShouldThreadTerminate.load() == false) |
72 | { |
73 | bool should_exit = m_rThreadUpdate.Update(); |
74 | if (should_exit) { break; } |
75 | } |
76 |
|
77 | LOGGER.Log(Logger::DEBUG, "ThreadRunLoop(): Thread '{}' exiting", m_threadName); |
78 | m_aIsThreadRunning.store(false); |
79 | return; |
80 | } |
81 |
|