From 86300ccedfc5ccdace551ce76f9185513d736127 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Fri, 24 Feb 2017 15:05:28 +0200 Subject: [PATCH] [core] Add pause/resume to the Thread class Make a thread completely halt and not process any message on the message queue until resume() is called. Sending a sync message to a halted thread will result on a deadlock, thus the assertion. Deleting a paused thread will trigger a resume. --- src/mbgl/util/thread.hpp | 45 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp index b03c7f3e7..184c6a8a1 100644 --- a/src/mbgl/util/thread.hpp +++ b/src/mbgl/util/thread.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -9,6 +10,7 @@ #include #include #include +#include namespace mbgl { namespace util { @@ -47,6 +49,8 @@ public: // Invoke object->fn(args...) asynchronously, but wait for the result. template auto invokeSync(Fn fn, Args&&... args) { + assert(!paused); + using R = std::result_of_t; std::packaged_task task(std::bind(fn, object, args...)); std::future future = task.get_future(); @@ -54,7 +58,39 @@ public: return future.get(); } + void pause() { + MBGL_VERIFY_THREAD(tid); + + assert(!paused); + + paused = std::make_unique>(); + resumed = std::make_unique>(); + + auto pausing = paused->get_future(); + + loop->invoke([this] { + auto resuming = resumed->get_future(); + paused->set_value(); + resuming.get(); + }); + + pausing.get(); + } + + void resume() { + MBGL_VERIFY_THREAD(tid); + + assert(paused); + + resumed->set_value(); + + resumed.reset(); + paused.reset(); + } + private: + MBGL_STORE_THREAD(tid); + Thread(const Thread&) = delete; Thread(Thread&&) = delete; Thread& operator=(const Thread&) = delete; @@ -73,6 +109,9 @@ private: std::promise running; std::promise joinable; + std::unique_ptr> paused; + std::unique_ptr> resumed; + std::thread thread; Object* object = nullptr; @@ -119,6 +158,12 @@ void Thread::run(P&& params, std::index_sequence) { template Thread::~Thread() { + MBGL_VERIFY_THREAD(tid); + + if (paused) { + resume(); + } + loop->stop(); joinable.set_value(); thread.join();