From e4bff8be94c0db4f94e63ad448d0eeb869ccdbbd Mon Sep 17 00:00:00 2001 From: ShadowNinja Date: Tue, 7 Apr 2015 06:13:12 -0400 Subject: Clean up threading * Rename everything. * Strip J prefix. * Change UpperCamelCase functions to lowerCamelCase. * Remove global (!) semaphore count mutex on OSX. * Remove semaphore count getter (unused, unsafe, depended on internal API functions on Windows, and used a hack on OSX). * Add `Atomic`. * Make `Thread` handle thread names. * Add support for C++11 multi-threading. * Combine pthread and win32 sources. * Remove `ThreadStarted` (unused, unneeded). * Move some includes from the headers to the sources. * Move all of `Event` into its header (allows inlining with no new includes). * Make `Event` use `Semaphore` (except on Windows). * Move some porting functions into `Thread`. * Integrate logging with `Thread`. * Add threading test. --- src/util/container.h | 171 +++++++++++++++------------------------------------ src/util/numeric.cpp | 6 +- src/util/numeric.h | 4 +- src/util/thread.h | 60 ++++++++---------- 4 files changed, 77 insertions(+), 164 deletions(-) (limited to 'src/util') diff --git a/src/util/container.h b/src/util/container.h index 267d54c16..7f66b89ac 100644 --- a/src/util/container.h +++ b/src/util/container.h @@ -22,9 +22,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "../irrlichttypes.h" #include "../exceptions.h" -#include "../jthread/jmutex.h" -#include "../jthread/jmutexautolock.h" -#include "../jthread/jsemaphore.h" +#include "../threading/mutex.h" +#include "../threading/mutex_auto_lock.h" +#include "../threading/semaphore.h" #include #include #include @@ -81,111 +81,47 @@ template class MutexedMap { public: - MutexedMap() - { - } + MutexedMap() {} void set(const Key &name, const Value &value) { - JMutexAutoLock lock(m_mutex); - + MutexAutoLock lock(m_mutex); m_values[name] = value; } - bool get(const Key &name, Value *result) + bool get(const Key &name, Value *result) const { - JMutexAutoLock lock(m_mutex); - - typename std::map::iterator n; - n = m_values.find(name); - - if(n == m_values.end()) + MutexAutoLock lock(m_mutex); + typename std::map::const_iterator n = + m_values.find(name); + if (n == m_values.end()) return false; - - if(result != NULL) + if (result) *result = n->second; - return true; } - std::vector getValues() + std::vector getValues() const { + MutexAutoLock lock(m_mutex); std::vector result; - for(typename std::map::iterator - i = m_values.begin(); - i != m_values.end(); ++i){ - result.push_back(i->second); + for (typename std::map::const_iterator + it = m_values.begin(); + it != m_values.end(); ++it){ + result.push_back(it->second); } return result; } - void clear () - { - m_values.clear(); - } + void clear() { m_values.clear(); } private: std::map m_values; - JMutex m_mutex; + mutable Mutex m_mutex; }; -/* -Generates ids for comparable values. -Id=0 is reserved for "no value". -Is fast at: -- Returning value by id (very fast) -- Returning id by value -- Generating a new id for a value - -Is not able to: -- Remove an id/value pair (is possible to implement but slow) -*/ -template -class MutexedIdGenerator -{ -public: - MutexedIdGenerator() - { - } - - // Returns true if found - bool getValue(u32 id, T &value) - { - if(id == 0) - return false; - JMutexAutoLock lock(m_mutex); - if(m_id_to_value.size() < id) - return false; - value = m_id_to_value[id-1]; - return true; - } - - // If id exists for value, returns the id. - // Otherwise generates an id for the value. - u32 getId(const T &value) - { - JMutexAutoLock lock(m_mutex); - typename std::map::iterator n; - n = m_value_to_id.find(value); - if(n != m_value_to_id.end()) - return n->second; - m_id_to_value.push_back(value); - u32 new_id = m_id_to_value.size(); - m_value_to_id.insert(value, new_id); - return new_id; - } - -private: - JMutex m_mutex; - // Values are stored here at id-1 position (id 1 = [0]) - std::vector m_id_to_value; - std::map m_value_to_id; -}; - -/* -Thread-safe FIFO queue (well, actually a FILO also) -*/ +// Thread-safe Double-ended queue template class MutexedQueue @@ -194,19 +130,18 @@ public: template friend class RequestQueue; - MutexedQueue() - { - } - bool empty() + MutexedQueue() {} + bool empty() const { - JMutexAutoLock lock(m_mutex); - return (m_queue.size() == 0); + MutexAutoLock lock(m_mutex); + return m_queue.empty(); } + void push_back(T t) { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); m_queue.push_back(t); - m_size.Post(); + m_signal.post(); } /* this version of pop_front returns a empty element of T on timeout. @@ -214,37 +149,35 @@ public: */ T pop_frontNoEx(u32 wait_time_max_ms) { - if (m_size.Wait(wait_time_max_ms)) { - JMutexAutoLock lock(m_mutex); + if (m_signal.wait(wait_time_max_ms)) { + MutexAutoLock lock(m_mutex); T t = m_queue.front(); m_queue.pop_front(); return t; - } - else { + } else { return T(); } } T pop_front(u32 wait_time_max_ms) { - if (m_size.Wait(wait_time_max_ms)) { - JMutexAutoLock lock(m_mutex); + if (m_signal.wait(wait_time_max_ms)) { + MutexAutoLock lock(m_mutex); T t = m_queue.front(); m_queue.pop_front(); return t; - } - else { + } else { throw ItemNotFoundException("MutexedQueue: queue is empty"); } } T pop_frontNoEx() { - m_size.Wait(); + m_signal.wait(); - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); T t = m_queue.front(); m_queue.pop_front(); @@ -253,14 +186,13 @@ public: T pop_back(u32 wait_time_max_ms=0) { - if (m_size.Wait(wait_time_max_ms)) { - JMutexAutoLock lock(m_mutex); + if (m_signal.wait(wait_time_max_ms)) { + MutexAutoLock lock(m_mutex); T t = m_queue.back(); m_queue.pop_back(); return t; - } - else { + } else { throw ItemNotFoundException("MutexedQueue: queue is empty"); } } @@ -268,25 +200,24 @@ public: /* this version of pop_back returns a empty element of T on timeout. * Make sure default constructor of T creates a recognizable "empty" element */ - T pop_backNoEx(u32 wait_time_max_ms=0) + T pop_backNoEx(u32 wait_time_max_ms) { - if (m_size.Wait(wait_time_max_ms)) { - JMutexAutoLock lock(m_mutex); + if (m_signal.wait(wait_time_max_ms)) { + MutexAutoLock lock(m_mutex); T t = m_queue.back(); m_queue.pop_back(); return t; - } - else { + } else { return T(); } } T pop_backNoEx() { - m_size.Wait(); + m_signal.wait(); - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); T t = m_queue.back(); m_queue.pop_back(); @@ -294,19 +225,13 @@ public: } protected: - JMutex & getMutex() - { - return m_mutex; - } + Mutex &getMutex() { return m_mutex; } - std::deque & getQueue() - { - return m_queue; - } + std::deque &getQueue() { return m_queue; } std::deque m_queue; - JMutex m_mutex; - JSemaphore m_size; + mutable Mutex m_mutex; + Semaphore m_signal; }; template diff --git a/src/util/numeric.cpp b/src/util/numeric.cpp index 3fd1c9cf9..bfd5d6e38 100644 --- a/src/util/numeric.cpp +++ b/src/util/numeric.cpp @@ -23,17 +23,17 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "log.h" #include "../constants.h" // BS, MAP_BLOCKSIZE #include "../noise.h" // PseudoRandom, PcgRandom -#include "../jthread/jmutexautolock.h" +#include "../threading/mutex_auto_lock.h" #include #include std::map > FacePositionCache::m_cache; -JMutex FacePositionCache::m_cache_mutex; +Mutex FacePositionCache::m_cache_mutex; // Calculate the borders of a "d-radius" cube // TODO: Make it work without mutex and data races, probably thread-local std::vector FacePositionCache::getFacePositions(u16 d) { - JMutexAutoLock cachelock(m_cache_mutex); + MutexAutoLock cachelock(m_cache_mutex); if (m_cache.find(d) != m_cache.end()) return m_cache[d]; diff --git a/src/util/numeric.h b/src/util/numeric.h index 9fe08434f..8a17d892d 100644 --- a/src/util/numeric.h +++ b/src/util/numeric.h @@ -24,7 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "../irr_v2d.h" #include "../irr_v3d.h" #include "../irr_aabb3d.h" -#include "../jthread/jmutex.h" +#include "../threading/mutex.h" #include #include #include @@ -42,7 +42,7 @@ public: private: static void generateFacePosition(u16 d); static std::map > m_cache; - static JMutex m_cache_mutex; + static Mutex m_cache_mutex; }; class IndentationRaiser diff --git a/src/util/thread.h b/src/util/thread.h index b3a5e68a2..a32871aab 100644 --- a/src/util/thread.h +++ b/src/util/thread.h @@ -21,9 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #define UTIL_THREAD_HEADER #include "../irrlichttypes.h" -#include "../jthread/jthread.h" -#include "../jthread/jmutex.h" -#include "../jthread/jmutexautolock.h" +#include "../threading/thread.h" +#include "../threading/mutex.h" +#include "../threading/mutex_auto_lock.h" #include "porting.h" #include "log.h" @@ -36,27 +36,27 @@ public: T get() { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); return m_value; } void set(T value) { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); m_value = value; } // You'll want to grab this in a SharedPtr - JMutexAutoLock *getLock() + MutexAutoLock *getLock() { - return new JMutexAutoLock(m_mutex); + return new MutexAutoLock(m_mutex); } // You pretty surely want to grab the lock when accessing this T m_value; private: - JMutex m_mutex; + Mutex m_mutex; }; /* @@ -118,7 +118,7 @@ public: typename std::list >::iterator j; { - JMutexAutoLock lock(m_queue.getMutex()); + MutexAutoLock lock(m_queue.getMutex()); /* If the caller is already on the list, only update CallerData @@ -192,44 +192,33 @@ private: MutexedQueue > m_queue; }; -class UpdateThread : public JThread { +class UpdateThread : public Thread +{ public: - UpdateThread() {} - virtual ~UpdateThread() {} + UpdateThread(const std::string &name) : Thread(name + "Update") {} + ~UpdateThread() {} - void deferUpdate() - { - m_update_sem.Post(); - } + void deferUpdate() { m_update_sem.post(); } - void Stop() + void stop() { - JThread::Stop(); + Thread::stop(); // give us a nudge - m_update_sem.Post(); + m_update_sem.post(); } - void *Thread() + void *run() { - ThreadStarted(); - - const char *thread_name = getName(); - log_register_thread(thread_name); - porting::setThreadName(thread_name); - DSTACK(__FUNCTION_NAME); BEGIN_DEBUG_EXCEPTION_HANDLER - while (!StopRequested()) { - m_update_sem.Wait(); - - // Empty the queue, just in case doUpdate() is expensive - while (m_update_sem.GetValue()) - m_update_sem.Wait(); + while (!stopRequested()) { + m_update_sem.wait(); + // Set semaphore to 0 + while (m_update_sem.wait(0)); - if (StopRequested()) - break; + if (stopRequested()) break; doUpdate(); } @@ -241,10 +230,9 @@ public: protected: virtual void doUpdate() = 0; - virtual const char *getName() = 0; private: - JSemaphore m_update_sem; + Semaphore m_update_sem; }; #endif -- cgit v1.2.3