Allow ThreadPool to be created with < 2 ThreadCount
This commit is contained in:
parent
16f410c8ef
commit
6a8902ad51
4 changed files with 184 additions and 99 deletions
|
@ -93,7 +93,7 @@ namespace EC
|
||||||
std::size_t currentSize = 0;
|
std::size_t currentSize = 0;
|
||||||
std::unordered_set<std::size_t> deletedSet;
|
std::unordered_set<std::size_t> deletedSet;
|
||||||
|
|
||||||
ThreadPool<ThreadCount> threadPool;
|
std::unique_ptr<ThreadPool<ThreadCount> > threadPool;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*!
|
/*!
|
||||||
|
@ -105,6 +105,9 @@ namespace EC
|
||||||
Manager()
|
Manager()
|
||||||
{
|
{
|
||||||
resize(EC_INIT_ENTITIES_SIZE);
|
resize(EC_INIT_ENTITIES_SIZE);
|
||||||
|
if(ThreadCount >= 2) {
|
||||||
|
threadPool = std::make_unique<ThreadPool<ThreadCount> >();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -634,7 +637,7 @@ namespace EC
|
||||||
|
|
||||||
BitsetType signatureBitset =
|
BitsetType signatureBitset =
|
||||||
BitsetType::template generateBitset<Signature>();
|
BitsetType::template generateBitset<Signature>();
|
||||||
if(!useThreadPool)
|
if(!useThreadPool || !threadPool)
|
||||||
{
|
{
|
||||||
for(std::size_t i = 0; i < currentSize; ++i)
|
for(std::size_t i = 0; i < currentSize; ++i)
|
||||||
{
|
{
|
||||||
|
@ -673,7 +676,7 @@ namespace EC
|
||||||
std::get<2>(fnDataAr.at(i)) = &signatureBitset;
|
std::get<2>(fnDataAr.at(i)) = &signatureBitset;
|
||||||
std::get<3>(fnDataAr.at(i)) = {begin, end};
|
std::get<3>(fnDataAr.at(i)) = {begin, end};
|
||||||
std::get<4>(fnDataAr.at(i)) = userData;
|
std::get<4>(fnDataAr.at(i)) = userData;
|
||||||
threadPool.queueFn([&function] (void *ud) {
|
threadPool->queueFn([&function] (void *ud) {
|
||||||
auto *data = static_cast<TPFnDataType*>(ud);
|
auto *data = static_cast<TPFnDataType*>(ud);
|
||||||
for(std::size_t i = std::get<3>(*data).at(0);
|
for(std::size_t i = std::get<3>(*data).at(0);
|
||||||
i < std::get<3>(*data).at(1);
|
i < std::get<3>(*data).at(1);
|
||||||
|
@ -691,10 +694,10 @@ namespace EC
|
||||||
}
|
}
|
||||||
}, &fnDataAr.at(i));
|
}, &fnDataAr.at(i));
|
||||||
}
|
}
|
||||||
threadPool.wakeThreads();
|
threadPool->wakeThreads();
|
||||||
do {
|
do {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||||
} while(!threadPool.isQueueEmpty() && !threadPool.isAllThreadsWaiting());
|
} while(!threadPool->isQueueEmpty() && !threadPool->isAllThreadsWaiting());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,7 +756,7 @@ namespace EC
|
||||||
|
|
||||||
BitsetType signatureBitset =
|
BitsetType signatureBitset =
|
||||||
BitsetType::template generateBitset<Signature>();
|
BitsetType::template generateBitset<Signature>();
|
||||||
if(!useThreadPool)
|
if(!useThreadPool || !threadPool)
|
||||||
{
|
{
|
||||||
for(std::size_t i = 0; i < currentSize; ++i)
|
for(std::size_t i = 0; i < currentSize; ++i)
|
||||||
{
|
{
|
||||||
|
@ -792,7 +795,7 @@ namespace EC
|
||||||
std::get<3>(fnDataAr.at(i)) = {begin, end};
|
std::get<3>(fnDataAr.at(i)) = {begin, end};
|
||||||
std::get<4>(fnDataAr.at(i)) = userData;
|
std::get<4>(fnDataAr.at(i)) = userData;
|
||||||
std::get<5>(fnDataAr.at(i)) = function;
|
std::get<5>(fnDataAr.at(i)) = function;
|
||||||
threadPool.queueFn([] (void *ud) {
|
threadPool->queueFn([] (void *ud) {
|
||||||
auto *data = static_cast<TPFnDataType*>(ud);
|
auto *data = static_cast<TPFnDataType*>(ud);
|
||||||
for(std::size_t i = std::get<3>(*data).at(0);
|
for(std::size_t i = std::get<3>(*data).at(0);
|
||||||
i < std::get<3>(*data).at(1);
|
i < std::get<3>(*data).at(1);
|
||||||
|
@ -810,10 +813,10 @@ namespace EC
|
||||||
}
|
}
|
||||||
}, &fnDataAr.at(i));
|
}, &fnDataAr.at(i));
|
||||||
}
|
}
|
||||||
threadPool.wakeThreads();
|
threadPool->wakeThreads();
|
||||||
do {
|
do {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||||
} while(!threadPool.isQueueEmpty() && !threadPool.isAllThreadsWaiting());
|
} while(!threadPool->isQueueEmpty() && !threadPool->isAllThreadsWaiting());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -906,7 +909,7 @@ namespace EC
|
||||||
std::vector<std::size_t> matching,
|
std::vector<std::size_t> matching,
|
||||||
void* userData)
|
void* userData)
|
||||||
{
|
{
|
||||||
if(!useThreadPool)
|
if(!useThreadPool || !threadPool)
|
||||||
{
|
{
|
||||||
for(auto eid : matching)
|
for(auto eid : matching)
|
||||||
{
|
{
|
||||||
|
@ -939,7 +942,7 @@ namespace EC
|
||||||
std::get<2>(fnDataAr.at(i)) = {begin, end};
|
std::get<2>(fnDataAr.at(i)) = {begin, end};
|
||||||
std::get<3>(fnDataAr.at(i)) = userData;
|
std::get<3>(fnDataAr.at(i)) = userData;
|
||||||
std::get<4>(fnDataAr.at(i)) = &matching;
|
std::get<4>(fnDataAr.at(i)) = &matching;
|
||||||
threadPool.queueFn([function, helper] (void* ud) {
|
threadPool->queueFn([function, helper] (void* ud) {
|
||||||
auto *data = static_cast<TPFnDataType*>(ud);
|
auto *data = static_cast<TPFnDataType*>(ud);
|
||||||
for(std::size_t i = std::get<2>(*data).at(0);
|
for(std::size_t i = std::get<2>(*data).at(0);
|
||||||
i < std::get<2>(*data).at(1);
|
i < std::get<2>(*data).at(1);
|
||||||
|
@ -954,10 +957,10 @@ namespace EC
|
||||||
}
|
}
|
||||||
}, &fnDataAr.at(i));
|
}, &fnDataAr.at(i));
|
||||||
}
|
}
|
||||||
threadPool.wakeThreads();
|
threadPool->wakeThreads();
|
||||||
do {
|
do {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||||
} while(!threadPool.isQueueEmpty() && !threadPool.isAllThreadsWaiting());
|
} while(!threadPool->isQueueEmpty() && !threadPool->isAllThreadsWaiting());
|
||||||
}
|
}
|
||||||
})));
|
})));
|
||||||
|
|
||||||
|
@ -970,7 +973,7 @@ namespace EC
|
||||||
{
|
{
|
||||||
std::vector<std::vector<std::size_t> > matchingV(bitsets.size());
|
std::vector<std::vector<std::size_t> > matchingV(bitsets.size());
|
||||||
|
|
||||||
if(!useThreadPool)
|
if(!useThreadPool || !threadPool)
|
||||||
{
|
{
|
||||||
for(std::size_t i = 0; i < currentSize; ++i)
|
for(std::size_t i = 0; i < currentSize; ++i)
|
||||||
{
|
{
|
||||||
|
@ -1012,7 +1015,7 @@ namespace EC
|
||||||
std::get<3>(fnDataAr.at(i)) = &bitsets;
|
std::get<3>(fnDataAr.at(i)) = &bitsets;
|
||||||
std::get<4>(fnDataAr.at(i)) = &entities;
|
std::get<4>(fnDataAr.at(i)) = &entities;
|
||||||
std::get<5>(fnDataAr.at(i)) = &mutex;
|
std::get<5>(fnDataAr.at(i)) = &mutex;
|
||||||
threadPool.queueFn([] (void *ud) {
|
threadPool->queueFn([] (void *ud) {
|
||||||
auto *data = static_cast<TPFnDataType*>(ud);
|
auto *data = static_cast<TPFnDataType*>(ud);
|
||||||
for(std::size_t i = std::get<1>(*data).at(0);
|
for(std::size_t i = std::get<1>(*data).at(0);
|
||||||
i < std::get<1>(*data).at(1);
|
i < std::get<1>(*data).at(1);
|
||||||
|
@ -1033,10 +1036,10 @@ namespace EC
|
||||||
}
|
}
|
||||||
}, &fnDataAr.at(i));
|
}, &fnDataAr.at(i));
|
||||||
}
|
}
|
||||||
threadPool.wakeThreads();
|
threadPool->wakeThreads();
|
||||||
do {
|
do {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||||
} while(!threadPool.isQueueEmpty() && !threadPool.isAllThreadsWaiting());
|
} while(!threadPool->isQueueEmpty() && !threadPool->isAllThreadsWaiting());
|
||||||
}
|
}
|
||||||
|
|
||||||
return matchingV;
|
return matchingV;
|
||||||
|
@ -1351,7 +1354,7 @@ namespace EC
|
||||||
});
|
});
|
||||||
|
|
||||||
// find and store entities matching signatures
|
// find and store entities matching signatures
|
||||||
if(!useThreadPool)
|
if(!useThreadPool || !threadPool)
|
||||||
{
|
{
|
||||||
for(std::size_t eid = 0; eid < currentSize; ++eid)
|
for(std::size_t eid = 0; eid < currentSize; ++eid)
|
||||||
{
|
{
|
||||||
|
@ -1394,7 +1397,7 @@ namespace EC
|
||||||
std::get<3>(fnDataAr.at(i)) = signatureBitsets;
|
std::get<3>(fnDataAr.at(i)) = signatureBitsets;
|
||||||
std::get<4>(fnDataAr.at(i)) = &mutex;
|
std::get<4>(fnDataAr.at(i)) = &mutex;
|
||||||
|
|
||||||
threadPool.queueFn([] (void *ud) {
|
threadPool->queueFn([] (void *ud) {
|
||||||
auto *data = static_cast<TPFnDataType*>(ud);
|
auto *data = static_cast<TPFnDataType*>(ud);
|
||||||
for(std::size_t i = std::get<1>(*data).at(0);
|
for(std::size_t i = std::get<1>(*data).at(0);
|
||||||
i < std::get<1>(*data).at(1);
|
i < std::get<1>(*data).at(1);
|
||||||
|
@ -1412,10 +1415,10 @@ namespace EC
|
||||||
}
|
}
|
||||||
}, &fnDataAr.at(i));
|
}, &fnDataAr.at(i));
|
||||||
}
|
}
|
||||||
threadPool.wakeThreads();
|
threadPool->wakeThreads();
|
||||||
do {
|
do {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||||
} while(!threadPool.isQueueEmpty() && !threadPool.isAllThreadsWaiting());
|
} while(!threadPool->isQueueEmpty() && !threadPool->isAllThreadsWaiting());
|
||||||
}
|
}
|
||||||
|
|
||||||
// call functions on matching entities
|
// call functions on matching entities
|
||||||
|
@ -1432,7 +1435,7 @@ namespace EC
|
||||||
EC::Meta::Morph<
|
EC::Meta::Morph<
|
||||||
SignatureComponents,
|
SignatureComponents,
|
||||||
ForMatchingSignatureHelper<> >;
|
ForMatchingSignatureHelper<> >;
|
||||||
if(!useThreadPool) {
|
if(!useThreadPool || !threadPool) {
|
||||||
for(const auto& id : multiMatchingEntities[index]) {
|
for(const auto& id : multiMatchingEntities[index]) {
|
||||||
if(isAlive(id)) {
|
if(isAlive(id)) {
|
||||||
Helper::call(id, *this, func, userData);
|
Helper::call(id, *this, func, userData);
|
||||||
|
@ -1459,7 +1462,7 @@ namespace EC
|
||||||
std::get<2>(fnDataAr.at(i)) = {begin, end};
|
std::get<2>(fnDataAr.at(i)) = {begin, end};
|
||||||
std::get<3>(fnDataAr.at(i)) = &multiMatchingEntities;
|
std::get<3>(fnDataAr.at(i)) = &multiMatchingEntities;
|
||||||
std::get<4>(fnDataAr.at(i)) = index;
|
std::get<4>(fnDataAr.at(i)) = index;
|
||||||
threadPool.queueFn([&func] (void *ud) {
|
threadPool->queueFn([&func] (void *ud) {
|
||||||
auto *data = static_cast<TPFnType*>(ud);
|
auto *data = static_cast<TPFnType*>(ud);
|
||||||
for(std::size_t i = std::get<2>(*data).at(0);
|
for(std::size_t i = std::get<2>(*data).at(0);
|
||||||
i < std::get<2>(*data).at(1);
|
i < std::get<2>(*data).at(1);
|
||||||
|
@ -1474,10 +1477,10 @@ namespace EC
|
||||||
}
|
}
|
||||||
}, &fnDataAr.at(i));
|
}, &fnDataAr.at(i));
|
||||||
}
|
}
|
||||||
threadPool.wakeThreads();
|
threadPool->wakeThreads();
|
||||||
do {
|
do {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||||
} while(!threadPool.isQueueEmpty() && !threadPool.isAllThreadsWaiting());
|
} while(!threadPool->isQueueEmpty() && !threadPool->isAllThreadsWaiting());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1544,7 +1547,7 @@ namespace EC
|
||||||
});
|
});
|
||||||
|
|
||||||
// find and store entities matching signatures
|
// find and store entities matching signatures
|
||||||
if(!useThreadPool)
|
if(!useThreadPool || !threadPool)
|
||||||
{
|
{
|
||||||
for(std::size_t eid = 0; eid < currentSize; ++eid)
|
for(std::size_t eid = 0; eid < currentSize; ++eid)
|
||||||
{
|
{
|
||||||
|
@ -1587,7 +1590,7 @@ namespace EC
|
||||||
std::get<3>(fnDataAr.at(i)) = signatureBitsets;
|
std::get<3>(fnDataAr.at(i)) = signatureBitsets;
|
||||||
std::get<4>(fnDataAr.at(i)) = &mutex;
|
std::get<4>(fnDataAr.at(i)) = &mutex;
|
||||||
|
|
||||||
threadPool.queueFn([] (void *ud) {
|
threadPool->queueFn([] (void *ud) {
|
||||||
auto *data = static_cast<TPFnDataType*>(ud);
|
auto *data = static_cast<TPFnDataType*>(ud);
|
||||||
for(std::size_t i = std::get<1>(*data).at(0);
|
for(std::size_t i = std::get<1>(*data).at(0);
|
||||||
i < std::get<1>(*data).at(1);
|
i < std::get<1>(*data).at(1);
|
||||||
|
@ -1605,10 +1608,10 @@ namespace EC
|
||||||
}
|
}
|
||||||
}, &fnDataAr.at(i));
|
}, &fnDataAr.at(i));
|
||||||
}
|
}
|
||||||
threadPool.wakeThreads();
|
threadPool->wakeThreads();
|
||||||
do {
|
do {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||||
} while(!threadPool.isQueueEmpty() && !threadPool.isAllThreadsWaiting());
|
} while(!threadPool->isQueueEmpty() && !threadPool->isAllThreadsWaiting());
|
||||||
}
|
}
|
||||||
|
|
||||||
// call functions on matching entities
|
// call functions on matching entities
|
||||||
|
@ -1625,7 +1628,7 @@ namespace EC
|
||||||
EC::Meta::Morph<
|
EC::Meta::Morph<
|
||||||
SignatureComponents,
|
SignatureComponents,
|
||||||
ForMatchingSignatureHelper<> >;
|
ForMatchingSignatureHelper<> >;
|
||||||
if(!useThreadPool)
|
if(!useThreadPool || !threadPool)
|
||||||
{
|
{
|
||||||
for(const auto& id : multiMatchingEntities[index])
|
for(const auto& id : multiMatchingEntities[index])
|
||||||
{
|
{
|
||||||
|
@ -1657,7 +1660,7 @@ namespace EC
|
||||||
std::get<2>(fnDataAr.at(i)) = {begin, end};
|
std::get<2>(fnDataAr.at(i)) = {begin, end};
|
||||||
std::get<3>(fnDataAr.at(i)) = &multiMatchingEntities;
|
std::get<3>(fnDataAr.at(i)) = &multiMatchingEntities;
|
||||||
std::get<4>(fnDataAr.at(i)) = index;
|
std::get<4>(fnDataAr.at(i)) = index;
|
||||||
threadPool.queueFn([&func] (void *ud) {
|
threadPool->queueFn([&func] (void *ud) {
|
||||||
auto *data = static_cast<TPFnType*>(ud);
|
auto *data = static_cast<TPFnType*>(ud);
|
||||||
for(std::size_t i = std::get<2>(*data).at(0);
|
for(std::size_t i = std::get<2>(*data).at(0);
|
||||||
i < std::get<2>(*data).at(1);
|
i < std::get<2>(*data).at(1);
|
||||||
|
@ -1672,10 +1675,10 @@ namespace EC
|
||||||
}
|
}
|
||||||
}, &fnDataAr.at(i));
|
}, &fnDataAr.at(i));
|
||||||
}
|
}
|
||||||
threadPool.wakeThreads();
|
threadPool->wakeThreads();
|
||||||
do {
|
do {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||||
} while(!threadPool.isQueueEmpty() && !threadPool.isAllThreadsWaiting());
|
} while(!threadPool->isQueueEmpty() && !threadPool->isAllThreadsWaiting());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1694,7 +1697,7 @@ namespace EC
|
||||||
template <typename Signature>
|
template <typename Signature>
|
||||||
void forMatchingSimple(ForMatchingFn fn, void *userData = nullptr, const bool useThreadPool = false) {
|
void forMatchingSimple(ForMatchingFn fn, void *userData = nullptr, const bool useThreadPool = false) {
|
||||||
const BitsetType signatureBitset = BitsetType::template generateBitset<Signature>();
|
const BitsetType signatureBitset = BitsetType::template generateBitset<Signature>();
|
||||||
if(!useThreadPool) {
|
if(!useThreadPool || !threadPool) {
|
||||||
for(std::size_t i = 0; i < currentSize; ++i) {
|
for(std::size_t i = 0; i < currentSize; ++i) {
|
||||||
if(!std::get<bool>(entities[i])) {
|
if(!std::get<bool>(entities[i])) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1723,7 +1726,7 @@ namespace EC
|
||||||
std::get<2>(fnDataAr.at(i)) = &signatureBitset;
|
std::get<2>(fnDataAr.at(i)) = &signatureBitset;
|
||||||
std::get<3>(fnDataAr.at(i)) = {begin, end};
|
std::get<3>(fnDataAr.at(i)) = {begin, end};
|
||||||
std::get<4>(fnDataAr.at(i)) = userData;
|
std::get<4>(fnDataAr.at(i)) = userData;
|
||||||
threadPool.queueFn([&fn] (void *ud) {
|
threadPool->queueFn([&fn] (void *ud) {
|
||||||
auto *data = static_cast<TPFnDataType*>(ud);
|
auto *data = static_cast<TPFnDataType*>(ud);
|
||||||
for(std::size_t i = std::get<3>(*data).at(0);
|
for(std::size_t i = std::get<3>(*data).at(0);
|
||||||
i < std::get<3>(*data).at(1);
|
i < std::get<3>(*data).at(1);
|
||||||
|
@ -1736,10 +1739,10 @@ namespace EC
|
||||||
}
|
}
|
||||||
}, &fnDataAr.at(i));
|
}, &fnDataAr.at(i));
|
||||||
}
|
}
|
||||||
threadPool.wakeThreads();
|
threadPool->wakeThreads();
|
||||||
do {
|
do {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||||
} while(!threadPool.isQueueEmpty() && !threadPool.isAllThreadsWaiting());
|
} while(!threadPool->isQueueEmpty() && !threadPool->isAllThreadsWaiting());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1754,7 +1757,7 @@ namespace EC
|
||||||
*/
|
*/
|
||||||
template <typename Iterable>
|
template <typename Iterable>
|
||||||
void forMatchingIterable(Iterable iterable, ForMatchingFn fn, void* userData = nullptr, const bool useThreadPool = false) {
|
void forMatchingIterable(Iterable iterable, ForMatchingFn fn, void* userData = nullptr, const bool useThreadPool = false) {
|
||||||
if(!useThreadPool) {
|
if(!useThreadPool || !threadPool) {
|
||||||
bool isValid;
|
bool isValid;
|
||||||
for(std::size_t i = 0; i < currentSize; ++i) {
|
for(std::size_t i = 0; i < currentSize; ++i) {
|
||||||
if(!std::get<bool>(entities[i])) {
|
if(!std::get<bool>(entities[i])) {
|
||||||
|
@ -1793,7 +1796,7 @@ namespace EC
|
||||||
std::get<2>(fnDataAr.at(i)) = &iterable;
|
std::get<2>(fnDataAr.at(i)) = &iterable;
|
||||||
std::get<3>(fnDataAr.at(i)) = {begin, end};
|
std::get<3>(fnDataAr.at(i)) = {begin, end};
|
||||||
std::get<4>(fnDataAr.at(i)) = userData;
|
std::get<4>(fnDataAr.at(i)) = userData;
|
||||||
threadPool.queueFn([&fn] (void *ud) {
|
threadPool->queueFn([&fn] (void *ud) {
|
||||||
auto *data = static_cast<TPFnDataType*>(ud);
|
auto *data = static_cast<TPFnDataType*>(ud);
|
||||||
bool isValid;
|
bool isValid;
|
||||||
for(std::size_t i = std::get<3>(*data).at(0);
|
for(std::size_t i = std::get<3>(*data).at(0);
|
||||||
|
@ -1816,10 +1819,10 @@ namespace EC
|
||||||
}
|
}
|
||||||
}, &fnDataAr.at(i));
|
}, &fnDataAr.at(i));
|
||||||
}
|
}
|
||||||
threadPool.wakeThreads();
|
threadPool->wakeThreads();
|
||||||
do {
|
do {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||||
} while(!threadPool.isQueueEmpty() && !threadPool.isAllThreadsWaiting());
|
} while(!threadPool->isQueueEmpty() && !threadPool->isAllThreadsWaiting());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,16 +20,14 @@ namespace Internal {
|
||||||
using TPQueueType = std::queue<TPTupleType>;
|
using TPQueueType = std::queue<TPTupleType>;
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|
||||||
template <unsigned int SIZE, typename = void>
|
|
||||||
class ThreadPool;
|
|
||||||
|
|
||||||
template <unsigned int SIZE>
|
template <unsigned int SIZE>
|
||||||
class ThreadPool<SIZE, typename std::enable_if<(SIZE >= 2)>::type> {
|
class ThreadPool {
|
||||||
public:
|
public:
|
||||||
using THREADCOUNT = std::integral_constant<int, SIZE>;
|
using THREADCOUNT = std::integral_constant<int, SIZE>;
|
||||||
|
|
||||||
ThreadPool() : waitCount(0) {
|
ThreadPool() : waitCount(0) {
|
||||||
isAlive.store(true);
|
isAlive.store(true);
|
||||||
|
if(SIZE >= 2) {
|
||||||
for(unsigned int i = 0; i < SIZE; ++i) {
|
for(unsigned int i = 0; i < SIZE; ++i) {
|
||||||
threads.emplace_back([] (std::atomic_bool *isAlive,
|
threads.emplace_back([] (std::atomic_bool *isAlive,
|
||||||
std::condition_variable *cv,
|
std::condition_variable *cv,
|
||||||
|
@ -68,18 +66,22 @@ public:
|
||||||
*waitCount -= 1;
|
*waitCount -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, &isAlive, &cv, &cvMutex, &fnQueue, &queueMutex, &waitCount, &waitCountMutex);
|
}, &isAlive, &cv, &cvMutex, &fnQueue, &queueMutex, &waitCount,
|
||||||
|
&waitCountMutex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~ThreadPool() {
|
~ThreadPool() {
|
||||||
|
if(SIZE >= 2) {
|
||||||
isAlive.store(false);
|
isAlive.store(false);
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||||
cv.notify_all();
|
cv.notify_all();
|
||||||
for(auto &thread : threads) {
|
for(auto &thread : threads) {
|
||||||
thread.join();
|
thread.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void queueFn(std::function<void(void*)>&& fn, void *ud = nullptr) {
|
void queueFn(std::function<void(void*)>&& fn, void *ud = nullptr) {
|
||||||
std::lock_guard<std::mutex> lock(queueMutex);
|
std::lock_guard<std::mutex> lock(queueMutex);
|
||||||
|
@ -87,11 +89,33 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void wakeThreads(bool wakeAll = true) {
|
void wakeThreads(bool wakeAll = true) {
|
||||||
|
if(SIZE >= 2) {
|
||||||
|
// wake threads to pull functions from queue and run them
|
||||||
if(wakeAll) {
|
if(wakeAll) {
|
||||||
cv.notify_all();
|
cv.notify_all();
|
||||||
} else {
|
} else {
|
||||||
cv.notify_one();
|
cv.notify_one();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// pull functions from queue and run them on main thread
|
||||||
|
Internal::TPTupleType fnTuple;
|
||||||
|
bool hasFn;
|
||||||
|
do {
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(queueMutex);
|
||||||
|
if(!fnQueue.empty()) {
|
||||||
|
hasFn = true;
|
||||||
|
fnTuple = fnQueue.front();
|
||||||
|
fnQueue.pop();
|
||||||
|
} else {
|
||||||
|
hasFn = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(hasFn) {
|
||||||
|
std::get<0>(fnTuple)(std::get<1>(fnTuple));
|
||||||
|
}
|
||||||
|
} while(hasFn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int getWaitCount() {
|
int getWaitCount() {
|
||||||
|
@ -100,8 +124,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAllThreadsWaiting() {
|
bool isAllThreadsWaiting() {
|
||||||
|
if(SIZE >= 2) {
|
||||||
std::lock_guard<std::mutex> lock(waitCountMutex);
|
std::lock_guard<std::mutex> lock(waitCountMutex);
|
||||||
return waitCount == THREADCOUNT::value;
|
return waitCount == THREADCOUNT::value;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isQueueEmpty() {
|
bool isQueueEmpty() {
|
||||||
|
|
|
@ -1370,3 +1370,30 @@ TEST(EC, MultiThreadedForMatching) {
|
||||||
EXPECT_TRUE(manager.isAlive(first));
|
EXPECT_TRUE(manager.isAlive(first));
|
||||||
EXPECT_FALSE(manager.isAlive(second));
|
EXPECT_FALSE(manager.isAlive(second));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(EC, ManagerWithLowThreadCount) {
|
||||||
|
EC::Manager<ListComponentsAll, ListTagsAll, 1> manager;
|
||||||
|
|
||||||
|
std::array<std::size_t, 10> entities;
|
||||||
|
for(auto &id : entities) {
|
||||||
|
id = manager.addEntity();
|
||||||
|
manager.addComponent<C0>(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto &id : entities) {
|
||||||
|
auto *component = manager.getEntityComponent<C0>(id);
|
||||||
|
EXPECT_EQ(component->x, 0);
|
||||||
|
EXPECT_EQ(component->y, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.forMatchingSignature<EC::Meta::TypeList<C0> >([] (std::size_t /*id*/, void* /*ud*/, C0 *c) {
|
||||||
|
c->x += 1;
|
||||||
|
c->y += 1;
|
||||||
|
}, nullptr, true);
|
||||||
|
|
||||||
|
for(const auto &id : entities) {
|
||||||
|
auto *component = manager.getEntityComponent<C0>(id);
|
||||||
|
EXPECT_EQ(component->x, 1);
|
||||||
|
EXPECT_EQ(component->y, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,15 +2,42 @@
|
||||||
|
|
||||||
#include <EC/ThreadPool.hpp>
|
#include <EC/ThreadPool.hpp>
|
||||||
|
|
||||||
//using OneThreadPool = EC::ThreadPool<1>;
|
using OneThreadPool = EC::ThreadPool<1>;
|
||||||
using ThreeThreadPool = EC::ThreadPool<3>;
|
using ThreeThreadPool = EC::ThreadPool<3>;
|
||||||
|
|
||||||
//TEST(ECThreadPool, CannotCompile) {
|
TEST(ECThreadPool, CannotCompile) {
|
||||||
// OneThreadPool tp;
|
OneThreadPool p;
|
||||||
//}
|
std::atomic_int data;
|
||||||
|
data.store(0);
|
||||||
TEST(ECThreadPool, Simple) {
|
const auto fn = [](void *ud) {
|
||||||
ThreeThreadPool p{};
|
auto *data = static_cast<std::atomic_int*>(ud);
|
||||||
|
data->fetch_add(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
p.queueFn(fn, &data);
|
||||||
|
|
||||||
|
p.wakeThreads();
|
||||||
|
|
||||||
|
do {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
} while(!p.isQueueEmpty() && !p.isAllThreadsWaiting());
|
||||||
|
|
||||||
|
ASSERT_EQ(data.load(), 1);
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < 10; ++i) {
|
||||||
|
p.queueFn(fn, &data);
|
||||||
|
}
|
||||||
|
p.wakeThreads();
|
||||||
|
|
||||||
|
do {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
} while(!p.isQueueEmpty() && !p.isAllThreadsWaiting());
|
||||||
|
|
||||||
|
ASSERT_EQ(data.load(), 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ECThreadPool, Simple) {
|
||||||
|
ThreeThreadPool p;
|
||||||
std::atomic_int data;
|
std::atomic_int data;
|
||||||
data.store(0);
|
data.store(0);
|
||||||
const auto fn = [](void *ud) {
|
const auto fn = [](void *ud) {
|
||||||
|
|
Loading…
Reference in a new issue