51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef UTIL_THREAD_HEADER
-#define UTIL_THREAD_HEADER
+#pragma once
-#include "../irrlichttypes.h"
-#include <jthread.h>
-#include <jmutex.h>
-#include <jmutexautolock.h>
+#include "irrlichttypes.h"
+#include "threading/thread.h"
+#include "threading/mutex_auto_lock.h"
+#include "porting.h"
+#include "log.h"
+#include "container.h"
template<typename T>
class MutexedVariable
{
public:
- MutexedVariable(T value):
+ MutexedVariable(const T &value):
m_value(value)
- {
- m_mutex.Init();
- }
+ {}
T get()
{
- JMutexAutoLock lock(m_mutex);
+ MutexAutoLock lock(m_mutex);
return m_value;
}
- void set(T value)
+ void set(const T &value)
{
- JMutexAutoLock lock(m_mutex);
+ MutexAutoLock lock(m_mutex);
m_value = value;
}
-
- // You'll want to grab this in a SharedPtr
- JMutexAutoLock * getLock()
- {
- return new JMutexAutoLock(m_mutex);
- }
-
+
// You pretty surely want to grab the lock when accessing this
T m_value;
-
private:
- JMutex m_mutex;
-};
-
-/*
- A base class for simple background thread implementation
-*/
-
-class SimpleThread : public JThread
-{
- bool run;
- JMutex run_mutex;
-
-public:
-
- SimpleThread():
- JThread(),
- run(true)
- {
- run_mutex.Init();
- }
-
- virtual ~SimpleThread()
- {}
-
- virtual void * Thread() = 0;
-
- bool getRun()
- {
- JMutexAutoLock lock(run_mutex);
- return run;
- }
- void setRun(bool a_run)
- {
- JMutexAutoLock lock(run_mutex);
- run = a_run;
- }
-
- void stop()
- {
- setRun(false);
- while(IsRunning())
- sleep_ms(100);
- }
+ std::mutex m_mutex;
};
/*
A single worker thread - multiple client threads queue framework.
*/
-
-template<typename Caller, typename Data>
-class CallerInfo
-{
-public:
- Caller caller;
- Data data;
-};
-
template<typename Key, typename T, typename Caller, typename CallerData>
-class GetResult
-{
+class GetResult {
public:
Key key;
T item;
- core::list<CallerInfo<Caller, CallerData> > callers;
+ std::pair<Caller, CallerData> caller;
};
template<typename Key, typename T, typename Caller, typename CallerData>
-class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
-{
+class ResultQueue : public MutexedQueue<GetResult<Key, T, Caller, CallerData> > {
+};
+
+template<typename Caller, typename Data, typename Key, typename T>
+class CallerInfo {
+public:
+ Caller caller;
+ Data data;
+ ResultQueue<Key, T, Caller, Data> *dest;
};
template<typename Key, typename T, typename Caller, typename CallerData>
-class GetRequest
-{
+class GetRequest {
public:
- GetRequest()
- {
- dest = NULL;
- }
- GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
- {
- dest = a_dest;
- }
- GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
- Key a_key)
- {
- dest = a_dest;
- key = a_key;
- }
- ~GetRequest()
+ GetRequest() = default;
+ ~GetRequest() = default;
+
+ GetRequest(const Key &a_key): key(a_key)
{
}
-
+
Key key;
- ResultQueue<Key, T, Caller, CallerData> *dest;
- core::list<CallerInfo<Caller, CallerData> > callers;
+ std::list<CallerInfo<Caller, CallerData, Key, T> > callers;
};
+/**
+ * Notes for RequestQueue usage
+ * @param Key unique key to identify a request for a specific resource
+ * @param T ?
+ * @param Caller unique id of calling thread
+ * @param CallerData data passed back to caller
+ */
template<typename Key, typename T, typename Caller, typename CallerData>
-class RequestQueue
-{
+class RequestQueue {
public:
- u32 size()
+ bool empty()
{
- return m_queue.size();
+ return m_queue.empty();
}
- void add(Key key, Caller caller, CallerData callerdata,
- ResultQueue<Key, T, Caller, CallerData> *dest)
+ void add(const Key &key, Caller caller, CallerData callerdata,
+ ResultQueue<Key, T, Caller, CallerData> *dest)
{
- JMutexAutoLock lock(m_queue.getMutex());
-
- /*
- If the caller is already on the list, only update CallerData
- */
- for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
- i = m_queue.getList().begin();
- i != m_queue.getList().end(); i++)
+ typename std::deque<GetRequest<Key, T, Caller, CallerData> >::iterator i;
+ typename std::list<CallerInfo<Caller, CallerData, Key, T> >::iterator j;
+
{
- GetRequest<Key, T, Caller, CallerData> &request = *i;
-
- if(request.key == key)
- {
- for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
- i = request.callers.begin();
- i != request.callers.end(); i++)
- {
- CallerInfo<Caller, CallerData> &ca = *i;
- if(ca.caller == caller)
- {
+ MutexAutoLock lock(m_queue.getMutex());
+
+ /*
+ If the caller is already on the list, only update CallerData
+ */
+ for (i = m_queue.getQueue().begin(); i != m_queue.getQueue().end(); ++i) {
+ GetRequest<Key, T, Caller, CallerData> &request = *i;
+ if (request.key != key)
+ continue;
+
+ for (j = request.callers.begin(); j != request.callers.end(); ++j) {
+ CallerInfo<Caller, CallerData, Key, T> &ca = *j;
+ if (ca.caller == caller) {
ca.data = callerdata;
return;
}
}
- CallerInfo<Caller, CallerData> ca;
+
+ CallerInfo<Caller, CallerData, Key, T> ca;
ca.caller = caller;
ca.data = callerdata;
+ ca.dest = dest;
request.callers.push_back(ca);
return;
}
GetRequest<Key, T, Caller, CallerData> request;
request.key = key;
- CallerInfo<Caller, CallerData> ca;
+ CallerInfo<Caller, CallerData, Key, T> ca;
ca.caller = caller;
ca.data = callerdata;
+ ca.dest = dest;
request.callers.push_back(ca);
- request.dest = dest;
-
- m_queue.getList().push_back(request);
+
+ m_queue.push_back(request);
+ }
+
+ GetRequest<Key, T, Caller, CallerData> pop(unsigned int timeout_ms)
+ {
+ return m_queue.pop_front(timeout_ms);
}
- GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
+ GetRequest<Key, T, Caller, CallerData> pop()
{
- return m_queue.pop_front(wait_if_empty);
+ return m_queue.pop_frontNoEx();
+ }
+
+ void pushResult(GetRequest<Key, T, Caller, CallerData> req, T res)
+ {
+ for (typename std::list<CallerInfo<Caller, CallerData, Key, T> >::iterator
+ i = req.callers.begin();
+ i != req.callers.end(); ++i) {
+ CallerInfo<Caller, CallerData, Key, T> &ca = *i;
+
+ GetResult<Key,T,Caller,CallerData> result;
+
+ result.key = req.key;
+ result.item = res;
+ result.caller.first = ca.caller;
+ result.caller.second = ca.data;
+
+ ca.dest->push_back(result);
+ }
}
private:
- MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
+ MutexedQueue<GetRequest<Key, T, Caller, CallerData> > m_queue;
};
-#endif
+class UpdateThread : public Thread
+{
+public:
+ UpdateThread(const std::string &name) : Thread(name + "Update") {}
+ ~UpdateThread() = default;
+
+ void deferUpdate() { m_update_sem.post(); }
+
+ void stop()
+ {
+ Thread::stop();
+
+ // give us a nudge
+ m_update_sem.post();
+ }
+
+ void *run()
+ {
+ BEGIN_DEBUG_EXCEPTION_HANDLER
+
+ while (!stopRequested()) {
+ m_update_sem.wait();
+ // Set semaphore to 0
+ while (m_update_sem.wait(0));
+
+ if (stopRequested()) break;
+
+ doUpdate();
+ }
+
+ END_DEBUG_EXCEPTION_HANDLER
+ return NULL;
+ }
+
+protected:
+ virtual void doUpdate() = 0;
+
+private:
+ Semaphore m_update_sem;
+};