@@ -65,26 +65,29 @@ namespace SharedUtil
6565#else
6666 using ReturnT = std::invoke_result_t <Func, Args...>;
6767#endif
68- auto ff = std::bind (std::forward<Func>(f), std::forward<Args>(args)...);
69- auto task = std::make_shared<std::packaged_task<ReturnT ()>>(ff);
70-
71- // Package the task in a wrapper with a common void result
72- // plus a skip flag for destruction without running the task
73- std::packaged_task<void (bool )> resultTask ([task](bool skip) {
74- if (!skip)
75- (*task)();
76- // task automatically deleted when shared_ptr goes out of scope
77- });
7868
79- // Add task to queue and return future
69+ auto ff = std::bind (std::forward<Func>(f), std::forward<Args>(args)...);
70+ auto task = std::make_shared<std::packaged_task<ReturnT ()>>(ff);
8071 std::future<ReturnT> res = task->get_future ();
72+
8173 {
8274 std::unique_lock<std::mutex> lock (m_mutex);
8375 if (m_exit)
8476 {
85- // Pool is shutting down - reject new tasks
86- throw std::runtime_error (" Cannot enqueue task: thread pool is shutting down" );
77+ // Return failed future instead of throwing (avoids crash if caller ignores result)
78+ lock.unlock ();
79+ std::promise<ReturnT> failedPromise;
80+ failedPromise.set_exception (std::make_exception_ptr (
81+ std::runtime_error (" Cannot enqueue task: thread pool is shutting down" )));
82+ return failedPromise.get_future ();
8783 }
84+
85+ // Wrap task with skip flag for shutdown cleanup
86+ std::packaged_task<void (bool )> resultTask ([task](bool skip) {
87+ if (!skip)
88+ (*task)();
89+ });
90+
8891 m_tasks.emplace (std::move (resultTask));
8992 }
9093 m_cv.notify_one ();
@@ -95,11 +98,11 @@ namespace SharedUtil
9598 {
9699 {
97100 std::unique_lock<std::mutex> lock (m_mutex);
98-
101+
99102 // Already shutting down or shut down
100103 if (m_exit)
101104 return ;
102-
105+
103106 m_exit = true ;
104107
105108 // Clear all remaining tasks (they will be destroyed automatically)
0 commit comments