4#include "Etterna/Globals/global.h"
5#include "Etterna/Singletons/PrefsManager.h"
12#include <condition_variable>
19 std::unique_lock<std::mutex> lk(_updatedMutex);
20 _updatedCV.wait_for(lk, std::chrono::milliseconds(100), [
this] {
21 return this->getUpdated();
24 void setUpdated(
bool b)
27 std::lock_guard<std::mutex> lk(_updatedMutex);
30 _updatedCV.notify_all();
32 auto getUpdated() ->
bool {
return _updated; }
33 std::atomic<int> _threadsFinished{ 0 };
34 std::atomic<int> _progress{ 0 };
35 std::mutex _updatedMutex;
36 std::condition_variable _updatedCV;
37 void* data{
nullptr };
40 std::atomic<bool> _updated{
false };
44using vectorIt =
typename std::vector<T>::iterator;
46using vectorRange = std::pair<vectorIt<T>, vectorIt<T>>;
50splitWorkLoad(std::vector<T>& v,
size_t elementsPerThread)
51 -> std::vector<vectorRange<T>>
53 std::vector<vectorRange<T>> ranges;
54 if (elementsPerThread <= 0 || elementsPerThread >= v.size()) {
55 ranges.push_back(std::make_pair(v.begin(), v.end()));
59 size_t range_count = (v.size() + 1) / elementsPerThread + 1;
60 size_t ePT = v.size() / range_count;
62 ranges.push_back(std::make_pair(v.begin(), v.end()));
67 vectorIt<T> b = v.begin();
69 for (i = 0; i < v.size() - ePT; i += ePT)
70 ranges.push_back(std::make_pair(b + i, b + i + ePT));
72 ranges.push_back(std::make_pair(b + i, v.end()));
78parallelExecution(std::vector<T> vec,
79 std::function<
void(
int)> update,
80 std::function<
void(vectorRange<T>,
ThreadData*)> exec,
84 PREFSMAN->ThreadsToUse <= 0
85 ? std::thread::hardware_concurrency()
86 : PREFSMAN->ThreadsToUse <
87 static_cast<int>(std::thread::hardware_concurrency())
88 ? PREFSMAN->ThreadsToUse
89 : static_cast<int>(std::thread::hardware_concurrency());
90 std::vector<vectorRange<T>> workloads =
91 splitWorkLoad(vec,
static_cast<size_t>(vec.size() / THREADS));
94 auto threadCallback = [&data, &exec](vectorRange<T> workload) {
95 exec(workload, &data);
96 data._threadsFinished++;
97 data.setUpdated(
true);
99 std::vector<std::thread> threadpool;
100 for (
auto& workload : workloads)
101 threadpool.emplace_back(std::thread(threadCallback, workload));
102 while (data._threadsFinished < (
int)workloads.size()) {
103 data.waitForUpdate();
104 update(data._progress);
105 data.setUpdated(
false);
107 for (
auto& thread : threadpool)
112parallelExecution(std::vector<T> vec,
113 std::function<
void(
int)> update,
114 std::function<
void(vectorRange<T>,
ThreadData)> exec)
116 parallelExecution(vec, update, exec,
nullptr);
121parallelExecution(std::vector<T> vec,
122 std::function<
void(vectorRange<T>,
ThreadData*)> exec)
125 PREFSMAN->ThreadsToUse <= 0
126 ? std::thread::hardware_concurrency()
127 : PREFSMAN->ThreadsToUse <
128 static_cast<int>(std::thread::hardware_concurrency())
129 ? PREFSMAN->ThreadsToUse
130 : static_cast<int>(std::thread::hardware_concurrency());
131 std::vector<vectorRange<T>> workloads =
132 splitWorkLoad(vec,
static_cast<size_t>(vec.size() / THREADS));
134 auto threadCallback = [&data, &exec](vectorRange<T> workload) {
135 exec(workload, &data);
136 data._threadsFinished++;
137 data.setUpdated(
true);
139 std::vector<std::thread> threadpool;
140 for (
auto& workload : workloads)
141 threadpool.emplace_back(std::thread(threadCallback, workload));
142 while (data._threadsFinished < (
int)workloads.size()) {
143 data.waitForUpdate();
144 data.setUpdated(
false);
146 for (
auto& thread : threadpool)
161 void SetName(
const std::string& n) { m_sName = n; }
162 [[nodiscard]]
auto GetName()
const -> std::string {
return m_sName; }
163 void Create(
int (*fn)(
void*),
void* data);
165 void Halt(
bool Kill =
false);
170 static void HaltAllThreads(
bool Kill =
false);
173 static void ResumeAllThreads();
175 static auto GetCurrentThreadID() -> uint64_t;
177 static auto GetCurrentThreadName() ->
const char*;
178 static auto GetThreadNameByID(uint64_t iID) ->
const char*;
179 static auto EnumThreadIDs(
int n, uint64_t& iID) -> bool;
181 [[nodiscard]]
auto IsCreated()
const ->
bool {
return m_pSlot !=
nullptr; }
187 static auto GetSupportsTLS() ->
bool {
return s_bSystemSupportsTLS; }
188 static void SetSupportsTLS(
bool b) { s_bSystemSupportsTLS = b; }
190 static auto GetIsShowingDialog() ->
bool {
return s_bIsShowingDialog; }
191 static void SetIsShowingDialog(
bool b) { s_bIsShowingDialog = b; }
192 static auto GetInvalidThreadID() -> uint64_t;
198 static bool s_bSystemSupportsTLS;
199 static bool s_bIsShowingDialog;
234 [[nodiscard]]
auto GetName()
const -> std::string {
return m_sName; }
235 void SetName(
const std::string& s) { m_sName = s; }
237 virtual auto TryLock() -> bool;
238 virtual void Unlock();
239 [[nodiscard]]
virtual auto IsLockedByThisThread()
const -> bool;
251 void MarkLockedMutex();
288 , locked_at(cpy.locked_at)
305#define LockMut(m) LockMutex SM_UNIQUE_NAME(LocalLock)(m, __FILE__, __LINE__)
320 auto Wait(
float timeout = 0.F) -> bool;
323 [[nodiscard]]
auto WaitTimeoutSupported()
const -> bool;
336 RageSemaphore(
const std::string& sName,
int iInitialValue = 0);
339 [[nodiscard]]
auto GetName()
const -> std::string {
return m_sName; }
340 [[nodiscard]]
auto GetValue()
const -> int;
342 void Wait(
bool bFailOnTimeout =
true);
343 auto TryWait() -> bool;
Lock a mutex on construction, unlock it on destruction.
Definition RageThreads.h:264
void Unlock()
Unlock the mutex (before this would normally go out of scope).
Definition RageThreads.cpp:526
Definition RageThreads.h:309
Definition RageThreads.h:232
Definition RageThreads.h:334
Register a thread created outside of RageThread.
Definition RageThreads.h:211
Thread, mutex, semaphore, and event classes.
Definition RageThreads.h:155
Definition RageThreads.h:15
Definition RageThreads.cpp:39