SW Task Event Loop Framework v1.0.0
High-performance C++ asynchronous event loop framework with timer management and promise-based programming
Loading...
Searching...
No Matches
CpuTaskExecutor.tpp
Go to the documentation of this file.
1/**
2 * @file CpuTaskExecutor.tpp
3 * @brief Template implementation for CpuTaskExecutor - async CPU-bound task execution with timeout support
4 * @author Tran Anh Tai
5 * @date 9/2025
6 * @version 1.0.0
7 */
8
9 #pragma once
10 #include "Promise.h"
11 #include "SLLooper.h"
12 #include "CpuTaskExecutor.h"
13 #include <thread>
14 #include <future>
15 #include <string>
16
17 namespace swt {
18
19 /**
20 * @brief Execute CPU-bound task asynchronously without timeout
21 * @tparam Func Function type (auto-deduced)
22 * @param resultLooper SLLooper instance for result callback execution
23 * @param func CPU-intensive function to execute in separate thread
24 * @return Promise<ReturnType> Promise for result retrieval and continuation chaining
25 *
26 * Executes CPU-intensive tasks in a separate thread to avoid blocking the main
27 * event loop. The function is executed asynchronously using std::async with
28 * std::launch::async policy to guarantee separate thread execution. Results
29 * are delivered back to the specified event loop thread for thread-safe
30 * callback execution.
31 *
32 * Key implementation details:
33 * - **Separate thread**: Uses std::async with std::launch::async for guaranteed thread
34 * - **Thread-safe results**: Results posted back to specified SLLooper thread
35 * - **Exception safety**: Automatic exception capture and propagation
36 * - **Void support**: Template specialization handles void-returning functions
37 * - **Move semantics**: Efficient parameter and result transfer
38 * - **Fire-and-forget**: std::future is stored but not waited on (Promise coordination)
39 *
40 * Execution flow:
41 * 1. Create promise for result coordination
42 * 2. Launch async task in separate thread
43 * 3. Execute function and capture result/exception
44 * 4. Post result back to event loop thread via SLLooper
45 * 5. Resolve promise in event loop thread context
46 *
47 * @code{.cpp}
48 * auto promise = CpuTaskExecutor::executeAsync(looper, []() {
49 * // CPU-intensive computation
50 * return fibonacci(45); // This runs in separate thread
51 * });
52 *
53 * promise.then(looper, [](long result) {
54 * // This callback runs in event loop thread
55 * std::cout << "Fibonacci result: " << result << std::endl;
56 * }).catch_error(looper, [](std::exception_ptr ex) {
57 * std::cerr << "Computation failed!" << std::endl;
58 * });
59 * @endcode
60 *
61 * @note Function executes in separate thread - ensure thread safety
62 * @note Result callbacks execute in specified SLLooper thread context
63 * @note std::future is intentionally not waited on - Promise provides coordination
64 * @warning Avoid capturing SLLooper or other event loop objects in func
65 *
66 * @see \ref swt::CpuTaskExecutor "CpuTaskExecutor", \ref swt::Promise "Promise", \ref swt::SLLooper "SLLooper"
67 */
68 template<typename Func>
69 auto CpuTaskExecutor::executeAsync(std::shared_ptr<SLLooper> resultLooper,
70 Func&& func)
71 -> Promise<decltype(func())> {
72
73 using ReturnType = decltype(func());
74 auto promise = resultLooper->createPromise<ReturnType>();
75
76 // Launch async task - std::future stored to prevent immediate destruction
77 // but not waited on since Promise provides coordination mechanism
78 auto asyncFuture = std::async(std::launch::async, [promise, func = std::forward<Func>(func), resultLooper]() mutable {
79 try {
80 if constexpr (std::is_void_v<ReturnType>) {
81 // Handle void-returning function
82 func();
83 // Post success result back to event loop thread
84 resultLooper->post([promise]() mutable {
85 promise.set_value();
86 });
87 } else {
88 // Handle value-returning function
89 auto result = func();
90 // Post result back to event loop thread with move semantics
91 resultLooper->post([promise, result = std::move(result)]() mutable {
92 promise.set_value(std::move(result));
93 });
94 }
95 } catch (...) {
96 // Capture any exception thrown during execution
97 auto exception = std::current_exception();
98 // Post exception back to event loop thread
99 resultLooper->post([promise, exception]() mutable {
100 promise.set_exception(exception);
101 });
102 }
103 });
104
105 // Suppress unused variable warning - future is intentionally not waited on
106 // Promise mechanism provides the coordination, not std::future
107 (void)asyncFuture;
108
109 return promise;
110 }
111
112 /**
113 * @brief Execute CPU-bound task asynchronously with timeout protection
114 * @tparam Func Function type (auto-deduced)
115 * @param resultLooper SLLooper instance for result callback execution
116 * @param func CPU-intensive function to execute in separate thread
117 * @param timeout Maximum execution time before task is considered failed
118 * @return Promise<ReturnType> Promise for result retrieval and continuation chaining
119 *
120 * Executes CPU-intensive tasks with timeout protection to prevent runaway
121 * computations from hanging the application. Uses a two-level async approach:
122 * an outer async task manages timeout detection, while an inner async task
123 * executes the actual function. If the function doesn't complete within the
124 * timeout, a CpuTaskTimeoutException is generated.
125 *
126 * Key implementation Details:
127 * - **Timeout protection**: std::future::wait_for with timeout detection
128 * - **Two-level async**: Outer timeout management, inner task execution
129 * - **Exception types**: CpuTaskTimeoutException for timeout vs function exceptions
130 * - **Resource cleanup**: Timeout tasks are abandoned but system handles cleanup
131 * - **Thread safety**: Same result posting mechanism as non-timeout version
132 *
133 * Timeout behavior:
134 * - **Within timeout**: Normal result/exception delivery via Promise
135 * - **Timeout exceeded**: CpuTaskTimeoutException delivered via Promise
136 * - **Background cleanup**: System handles cleanup of abandoned timeout tasks
137 *
138 * @code{.cpp}
139 * auto promise = CpuTaskExecutor::executeAsync(looper, []() {
140 * return longRunningComputation(); // May take a long time
141 * }, 5000ms); // 5 second timeout
142 *
143 * promise.then(looper, [](auto result) {
144 * std::cout << "Completed in time: " << result << std::endl;
145 * }).catch_error(looper, [](std::exception_ptr ex) {
146 * try {
147 * std::rethrow_exception(ex);
148 * } catch (const CpuTaskTimeoutException& timeout) {
149 * std::cerr << "Task timed out: " << timeout.what() << std::endl;
150 * } catch (const std::exception& other) {
151 * std::cerr << "Task failed: " << other.what() << std::endl;
152 * }
153 * });
154 * @endcode
155 *
156 * @note Timeout detection uses std::future::wait_for for precision
157 * @note Timed-out tasks continue running but results are discarded
158 * @note CpuTaskTimeoutException provides timeout duration information
159 * @warning Long-running tasks may continue executing after timeout
160 *
161 * @see \ref swt::CpuTaskTimeoutException "CpuTaskTimeoutException", \ref swt::Promise "Promise", \ref swt::SLLooper "SLLooper"
162 */
163 template<typename Func>
164 auto CpuTaskExecutor::executeAsync(std::shared_ptr<SLLooper> resultLooper,
165 Func&& func,
166 std::chrono::milliseconds timeout)
167 -> Promise<decltype(func())> {
168
169 using ReturnType = decltype(func());
170 auto promise = resultLooper->createPromise<ReturnType>();
171
172 // Launch timeout management task
173 auto asyncFuture = std::async(std::launch::async, [promise, func = std::forward<Func>(func), resultLooper, timeout]() mutable {
174 try {
175 // Launch inner task for actual function execution
176 auto taskFuture = std::async(std::launch::async, std::move(func));
177
178 // Wait for completion or timeout
179 if (taskFuture.wait_for(timeout) == std::future_status::timeout) {
180 // Timeout occurred - create timeout exception
181 auto timeoutException = std::make_exception_ptr(
182 CpuTaskTimeoutException("CPU task timeout after " +
183 std::to_string(timeout.count()) + "ms"));
184 // Post timeout exception back to event loop thread
185 resultLooper->post([promise, timeoutException]() mutable {
186 promise.set_exception(timeoutException);
187 });
188 return; // Exit timeout management task
189 }
190
191 // Task completed within timeout - retrieve result
192 if constexpr (std::is_void_v<ReturnType>) {
193 // Handle void-returning function
194 taskFuture.get(); // May throw if function threw
195 // Post success result back to event loop thread
196 resultLooper->post([promise]() mutable {
197 promise.set_value();
198 });
199 } else {
200 // Handle value-returning function
201 auto result = taskFuture.get(); // May throw if function threw
202 // Post result back to event loop thread
203 resultLooper->post([promise, result = std::move(result)]() mutable {
204 promise.set_value(std::move(result));
205 });
206 }
207
208 } catch (...) {
209 // Capture any exception (from taskFuture.get() or other operations)
210 auto exception = std::current_exception();
211 // Post exception back to event loop thread
212 resultLooper->post([promise, exception]() mutable {
213 promise.set_exception(exception);
214 });
215 }
216 });
217
218 // Suppress unused variable warning - future provides timeout management
219 // but Promise provides the primary coordination mechanism
220 (void)asyncFuture;
221
222 return promise;
223 }
224
225 } // namespace swt