thread.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. Minetest
  3. Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #pragma once
  17. #include "../irrlichttypes.h"
  18. #include "../threading/thread.h"
  19. #include "../threading/mutex_auto_lock.h"
  20. #include "porting.h"
  21. #include "log.h"
  22. #include "container.h"
  23. template<typename T>
  24. class MutexedVariable
  25. {
  26. public:
  27. MutexedVariable(const T &value):
  28. m_value(value)
  29. {}
  30. T get()
  31. {
  32. MutexAutoLock lock(m_mutex);
  33. return m_value;
  34. }
  35. void set(const T &value)
  36. {
  37. MutexAutoLock lock(m_mutex);
  38. m_value = value;
  39. }
  40. // You pretty surely want to grab the lock when accessing this
  41. T m_value;
  42. private:
  43. std::mutex m_mutex;
  44. };
  45. /*
  46. A single worker thread - multiple client threads queue framework.
  47. */
  48. template<typename Key, typename T, typename Caller, typename CallerData>
  49. class GetResult {
  50. public:
  51. Key key;
  52. T item;
  53. std::pair<Caller, CallerData> caller;
  54. };
  55. template<typename Key, typename T, typename Caller, typename CallerData>
  56. class ResultQueue : public MutexedQueue<GetResult<Key, T, Caller, CallerData> > {
  57. };
  58. template<typename Caller, typename Data, typename Key, typename T>
  59. class CallerInfo {
  60. public:
  61. Caller caller;
  62. Data data;
  63. ResultQueue<Key, T, Caller, Data> *dest;
  64. };
  65. template<typename Key, typename T, typename Caller, typename CallerData>
  66. class GetRequest {
  67. public:
  68. GetRequest() = default;
  69. ~GetRequest() = default;
  70. GetRequest(const Key &a_key): key(a_key)
  71. {
  72. }
  73. Key key;
  74. std::list<CallerInfo<Caller, CallerData, Key, T> > callers;
  75. };
  76. /**
  77. * Notes for RequestQueue usage
  78. * @param Key unique key to identify a request for a specific resource
  79. * @param T ?
  80. * @param Caller unique id of calling thread
  81. * @param CallerData data passed back to caller
  82. */
  83. template<typename Key, typename T, typename Caller, typename CallerData>
  84. class RequestQueue {
  85. public:
  86. bool empty()
  87. {
  88. return m_queue.empty();
  89. }
  90. void add(const Key &key, Caller caller, CallerData callerdata,
  91. ResultQueue<Key, T, Caller, CallerData> *dest)
  92. {
  93. typename std::deque<GetRequest<Key, T, Caller, CallerData> >::iterator i;
  94. typename std::list<CallerInfo<Caller, CallerData, Key, T> >::iterator j;
  95. {
  96. MutexAutoLock lock(m_queue.getMutex());
  97. /*
  98. If the caller is already on the list, only update CallerData
  99. */
  100. for (i = m_queue.getQueue().begin(); i != m_queue.getQueue().end(); ++i) {
  101. GetRequest<Key, T, Caller, CallerData> &request = *i;
  102. if (request.key != key)
  103. continue;
  104. for (j = request.callers.begin(); j != request.callers.end(); ++j) {
  105. CallerInfo<Caller, CallerData, Key, T> &ca = *j;
  106. if (ca.caller == caller) {
  107. ca.data = callerdata;
  108. return;
  109. }
  110. }
  111. CallerInfo<Caller, CallerData, Key, T> ca;
  112. ca.caller = caller;
  113. ca.data = callerdata;
  114. ca.dest = dest;
  115. request.callers.push_back(ca);
  116. return;
  117. }
  118. }
  119. /*
  120. Else add a new request to the queue
  121. */
  122. GetRequest<Key, T, Caller, CallerData> request;
  123. request.key = key;
  124. CallerInfo<Caller, CallerData, Key, T> ca;
  125. ca.caller = caller;
  126. ca.data = callerdata;
  127. ca.dest = dest;
  128. request.callers.push_back(ca);
  129. m_queue.push_back(request);
  130. }
  131. GetRequest<Key, T, Caller, CallerData> pop(unsigned int timeout_ms)
  132. {
  133. return m_queue.pop_front(timeout_ms);
  134. }
  135. GetRequest<Key, T, Caller, CallerData> pop()
  136. {
  137. return m_queue.pop_frontNoEx();
  138. }
  139. void pushResult(GetRequest<Key, T, Caller, CallerData> req, T res)
  140. {
  141. for (typename std::list<CallerInfo<Caller, CallerData, Key, T> >::iterator
  142. i = req.callers.begin();
  143. i != req.callers.end(); ++i) {
  144. CallerInfo<Caller, CallerData, Key, T> &ca = *i;
  145. GetResult<Key,T,Caller,CallerData> result;
  146. result.key = req.key;
  147. result.item = res;
  148. result.caller.first = ca.caller;
  149. result.caller.second = ca.data;
  150. ca.dest->push_back(result);
  151. }
  152. }
  153. private:
  154. MutexedQueue<GetRequest<Key, T, Caller, CallerData> > m_queue;
  155. };
  156. class UpdateThread : public Thread
  157. {
  158. public:
  159. UpdateThread(const std::string &name) : Thread(name + "Update") {}
  160. ~UpdateThread() = default;
  161. void deferUpdate() { m_update_sem.post(); }
  162. void stop()
  163. {
  164. Thread::stop();
  165. // give us a nudge
  166. m_update_sem.post();
  167. }
  168. void *run()
  169. {
  170. BEGIN_DEBUG_EXCEPTION_HANDLER
  171. while (!stopRequested()) {
  172. m_update_sem.wait();
  173. // Set semaphore to 0
  174. while (m_update_sem.wait(0));
  175. if (stopRequested()) break;
  176. doUpdate();
  177. }
  178. END_DEBUG_EXCEPTION_HANDLER
  179. return NULL;
  180. }
  181. protected:
  182. virtual void doUpdate() = 0;
  183. private:
  184. Semaphore m_update_sem;
  185. };