1 #include "RNSkDispatchQueue.h" 2 3 #include <memory> 4 #include <mutex> 5 #include <utility> 6 7 namespace RNSkia { 8 ~RNSkDispatchQueue()9RNSkDispatchQueue::~RNSkDispatchQueue() { 10 // Signal to dispatch threads that it's time to wrap up 11 std::unique_lock<std::mutex> lock(lock_); 12 quit_ = true; 13 lock.unlock(); 14 cv_.notify_all(); 15 16 // Wait for threads to finish before we exit 17 for (size_t i = 0; i < threads_.size(); i++) { 18 if (threads_[i].joinable()) { 19 threads_[i].join(); 20 } 21 } 22 } 23 RNSkDispatchQueue(std::string name,size_t thread_cnt)24RNSkDispatchQueue::RNSkDispatchQueue(std::string name, size_t thread_cnt) 25 : name_{std::move(name)}, threads_(thread_cnt) { 26 for (size_t i = 0; i < threads_.size(); i++) { 27 threads_[i] = 28 std::thread(&RNSkDispatchQueue::dispatch_thread_handler, this); 29 } 30 } 31 dispatch(const fp_t & op)32void RNSkDispatchQueue::dispatch(const fp_t &op) { 33 std::unique_lock<std::mutex> lock(lock_); 34 q_.push(op); 35 36 // Manual unlocking is done before notifying, to avoid waking up 37 // the waiting thread only to block again (see notify_one for details) 38 lock.unlock(); 39 cv_.notify_one(); 40 } 41 dispatch(fp_t && op)42void RNSkDispatchQueue::dispatch(fp_t &&op) { 43 std::unique_lock<std::mutex> lock(lock_); 44 q_.push(std::move(op)); 45 46 // Manual unlocking is done before notifying, to avoid waking up 47 // the waiting thread only to block again (see notify_one for details) 48 lock.unlock(); 49 cv_.notify_one(); 50 } 51 dispatch_thread_handler(void)52void RNSkDispatchQueue::dispatch_thread_handler(void) { 53 std::unique_lock<std::mutex> lock(lock_); 54 55 do { 56 // Wait until we have data or a quit signal 57 cv_.wait(lock, [this] { return (q_.size() || quit_); }); 58 59 // after wait, we own the lock 60 if (!quit_ && q_.size()) { 61 auto op = std::move(q_.front()); 62 q_.pop(); 63 64 // unlock now that we're done messing with the queue 65 lock.unlock(); 66 67 op(); 68 69 lock.lock(); 70 } 71 } while (!quit_); 72 } 73 } // namespace RNSkia 74