No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 

182 líneas
4.5 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010—2015 Sam Hocevar <sam@hocevar.net>
  5. // © 2014—2015 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
  6. //
  7. // This library is free software. It comes without any warranty, to
  8. // the extent permitted by applicable law. You can redistribute it
  9. // and/or modify it under the terms of the Do What the Fuck You Want
  10. // to Public License, Version 2, as published by the WTFPL Task Force.
  11. // See http://www.wtfpl.net/ for more details.
  12. //
  13. #include <lol/engine-internal.h>
  14. namespace lol
  15. {
  16. //BaseThreadManager -----------------------------------------------------------
  17. BaseThreadManager::BaseThreadManager(int thread_count)
  18. {
  19. m_thread_min = thread_count;
  20. m_thread_count = thread_count;
  21. }
  22. BaseThreadManager::BaseThreadManager(int thread_min, int thread_count)
  23. {
  24. m_thread_min = thread_min;
  25. m_thread_count = thread_count;
  26. }
  27. BaseThreadManager::~BaseThreadManager()
  28. {
  29. Stop();
  30. }
  31. //Initialize, Ticker::Ref and start the thread
  32. bool BaseThreadManager::Start()
  33. {
  34. if (m_threads.count() > 0)
  35. return false;
  36. //Add minimum threads
  37. m_threads.Resize(m_thread_count);
  38. AddThreads(m_thread_min);
  39. return true;
  40. }
  41. //Stop the threads
  42. bool BaseThreadManager::Stop()
  43. {
  44. if (m_threads.count() <= 0)
  45. return false;
  46. //Stop all threads
  47. StopThreads((int)m_threads.count());
  48. return true;
  49. }
  50. //----
  51. void BaseThreadManager::AddThreads(int nb)
  52. {
  53. //Don't add threads if not availables
  54. #if LOL_FEATURE_THREADS
  55. //Spawn worker threads and ...
  56. for (int i = 0; i < nb; i++)
  57. m_threads << new thread(std::bind(&BaseThreadManager::BaseThreadWork, this));
  58. //... Wait for their readiness.
  59. for (int i = 0; i < m_thread_count; i++)
  60. m_spawnqueue.pop();
  61. #endif //LOL_FEATURE_THREADS
  62. }
  63. //----
  64. void BaseThreadManager::StopThreads(int nb)
  65. {
  66. //Don't stop threads if not availables
  67. #if LOL_FEATURE_THREADS
  68. //Signal worker threads for completion and ...
  69. ThreadJob stop_job(ThreadJobType::THREAD_STOP);
  70. for (int i = 0; i < nb; i++)
  71. m_jobqueue.push(&stop_job);
  72. //... Wait for them to quit.
  73. for (int i = 0; i < nb; i++)
  74. m_donequeue.pop();
  75. #endif //LOL_FEATURE_THREADS
  76. }
  77. //Work stuff
  78. bool BaseThreadManager::AddWork(ThreadJob* job)
  79. {
  80. if (m_jobqueue.try_push(job))
  81. return true;
  82. return false;
  83. }
  84. //----
  85. bool BaseThreadManager::FetchResult(array<ThreadJob*>& results)
  86. {
  87. ThreadJob* result;
  88. while (m_resultqueue.try_pop(result))
  89. results << result;
  90. return results.count() > 0;
  91. }
  92. //Base thread work function
  93. void BaseThreadManager::BaseThreadWork()
  94. {
  95. #if !LOL_FEATURE_THREADS
  96. //Register that the thread has started
  97. m_spawnqueue.push(ThreadStatus::THREAD_STARTED);
  98. for ( ; ; )
  99. #endif //!LOL_FEATURE_THREADS
  100. {
  101. //Try to retrieve a job
  102. ThreadJob* job = m_jobqueue.pop();
  103. //Stop thread
  104. if (job->GetJobType() == ThreadJobType::THREAD_STOP)
  105. {
  106. #if !LOL_FEATURE_THREADS
  107. break;
  108. #endif //!LOL_FEATURE_THREADS
  109. }
  110. //Or work
  111. else if (*job == ThreadJobType::WORK_TODO)
  112. {
  113. if (job->DoWork())
  114. job->SetJobType(ThreadJobType::WORK_DONE);
  115. else
  116. job->SetJobType(ThreadJobType::WORK_FAILED);
  117. m_resultqueue.push(job);
  118. }
  119. }
  120. #if !LOL_FEATURE_THREADS
  121. //Register that the thread has stopped
  122. m_donequeue.push(ThreadStatus::THREAD_STOPPED);
  123. #endif //!LOL_FEATURE_THREADS
  124. }
  125. //----
  126. void BaseThreadManager::TickGame(float seconds)
  127. {
  128. Entity::TickGame(seconds);
  129. //Start if needed
  130. Start();
  131. //Dispatch work task
  132. while (m_job_dispatch.Count() > 0 && AddWork(m_job_dispatch.Last()))
  133. m_job_dispatch.pop();
  134. //Execute one task per frame if thread are not available
  135. #if !LOL_FEATURE_THREADS
  136. BaseThreadWork();
  137. #endif // !LOL_FEATURE_THREADS
  138. array<ThreadJob*> result;
  139. //Fetch and treat results
  140. if (FetchResult(result))
  141. {
  142. for (int i = 0; i < result.count(); i++)
  143. {
  144. ThreadJob* job = result[i];
  145. if (job->GetJobType() == ThreadJobType::WORK_DONE)
  146. job->SetJobType(ThreadJobType::WORK_FETCHED);
  147. TreatResult(job);
  148. }
  149. }
  150. //Resize thread count if needed
  151. if (m_threads.count() > m_jobqueue.count() && m_threads.count() > m_thread_min)
  152. StopThreads((int)(m_threads.Count() - m_thread_min));
  153. else if (m_threads.count() < m_jobqueue.count())
  154. AddThreads((int)(lol::min(m_jobqueue.count(), (ptrdiff_t)m_thread_count) - m_threads.count()));
  155. }
  156. } /* namespace lol */