diff --git a/src/network/core/http_curl.cpp b/src/network/core/http_curl.cpp --- a/src/network/core/http_curl.cpp +++ b/src/network/core/http_curl.cpp @@ -230,8 +230,10 @@ void HttpThread() request->callback.OnFailure(); } - /* Wait till the callback tells us all data is dequeued. */ - request->callback.WaitTillEmpty(); + /* Wait till the callback tells us all data is dequeued, or _http_thread_exit has been set. */ + request->callback.WaitTillEmptyOrCondition([]() -> bool { + return _http_thread_exit; + }); } curl_easy_cleanup(curl); @@ -278,6 +280,11 @@ void NetworkHTTPUninitialize() _http_thread_exit = true; + /* Queues must be cleared (and the queue CV signalled) after _http_thread_exit is set to ensure that the HTTP thread can exit */ + for (auto &callback : _http_callbacks) { + callback->ClearQueue(); + } + { std::lock_guard lock(_http_mutex); _http_cv.notify_one(); diff --git a/src/network/core/http_shared.h b/src/network/core/http_shared.h --- a/src/network/core/http_shared.h +++ b/src/network/core/http_shared.h @@ -75,13 +75,15 @@ public: } /** - * Wait till the queue is dequeued. + * Wait till the queue is dequeued, or a condition is met. + * @param condition Condition functor. */ - void WaitTillEmpty() + template + void WaitTillEmptyOrCondition(T condition) { std::unique_lock lock(this->mutex); - while (!queue.empty()) { + while (!(queue.empty() || condition())) { this->queue_cv.wait(lock); } } @@ -95,6 +97,20 @@ public: return this->queue.empty(); } + + /** + * Clear everything in the queue. + * + * Should be called from the Game Thread. + */ + void ClearQueue() + { + std::lock_guard lock(this->mutex); + + this->queue.clear(); + this->queue_cv.notify_all(); + } + HTTPThreadSafeCallback(HTTPCallback *callback) : callback(callback) {} ~HTTPThreadSafeCallback()