Fix crash bug, improve Unit Test

Crash bug from improperly implemented std::lock_guard for multi-threaded
usage of forMatchingSignatures fixed.
This commit is contained in:
Stephen Seo 2017-11-10 13:19:50 +09:00
parent 0dba6874ad
commit 648e47aae9
2 changed files with 161 additions and 36 deletions

View file

@ -24,6 +24,10 @@
#include <queue> #include <queue>
#include <mutex> #include <mutex>
#ifndef NDEBUG
#include <iostream>
#endif
#include "Meta/Combine.hpp" #include "Meta/Combine.hpp"
#include "Meta/Matching.hpp" #include "Meta/Matching.hpp"
#include "Bitset.hpp" #include "Bitset.hpp"
@ -966,8 +970,6 @@ namespace EC
return forMatchingFunctions.erase(index) == 1; return forMatchingFunctions.erase(index) == 1;
} }
public:
/*! /*!
\brief Call multiple functions with mulitple signatures on all \brief Call multiple functions with mulitple signatures on all
living entities. living entities.
@ -1074,8 +1076,10 @@ namespace EC
& std::get<BitsetType>(entities[eid])) & std::get<BitsetType>(entities[eid]))
== signatureBitsets[i]) == signatureBitsets[i])
{ {
std::lock_guard<std::mutex>{sigsMutexes[i]}; std::lock_guard<std::mutex> guard(
sigsMutexes[i]);
multiMatchingEntities[i].push_back(eid); multiMatchingEntities[i].push_back(eid);
} }
} }
} }
@ -1101,19 +1105,20 @@ namespace EC
ForMatchingSignatureHelper<> >; ForMatchingSignatureHelper<> >;
using Index = EC::Meta::IndexOf<decltype(signature), using Index = EC::Meta::IndexOf<decltype(signature),
SigList>; SigList>;
constexpr std::size_t index = Index{};
if(threadCount <= 1) if(threadCount <= 1)
{ {
for(auto iter = multiMatchingEntities[Index{}].begin(); for(auto iter = multiMatchingEntities[index].begin();
iter != multiMatchingEntities[Index{}].end(); ++iter) iter != multiMatchingEntities[index].end(); ++iter)
{ {
Helper::call(*iter, *this, Helper::call(*iter, *this,
std::get<Index{}>(funcTuple)); std::get<index>(funcTuple));
} }
} }
else else
{ {
std::vector<std::thread> threads(threadCount); std::vector<std::thread> threads(threadCount);
std::size_t s = multiMatchingEntities[Index{}].size() std::size_t s = multiMatchingEntities[index].size()
/ threadCount; / threadCount;
for(std::size_t i = 0; i < threadCount; ++i) for(std::size_t i = 0; i < threadCount; ++i)
{ {
@ -1121,7 +1126,7 @@ namespace EC
std::size_t end; std::size_t end;
if(i == threadCount - 1) if(i == threadCount - 1)
{ {
end = multiMatchingEntities[Index{}].size(); end = multiMatchingEntities[index].size();
} }
else else
{ {
@ -1131,10 +1136,10 @@ namespace EC
[this, &multiMatchingEntities, &funcTuple] [this, &multiMatchingEntities, &funcTuple]
(std::size_t begin, std::size_t end) (std::size_t begin, std::size_t end)
{ {
for(std::size_t i = begin; i < end; ++i) for(std::size_t j = begin; j < end; ++j)
{ {
Helper::call(multiMatchingEntities[Index{}][i], Helper::call(multiMatchingEntities[index][j],
*this, std::get<Index{}>(funcTuple)); *this, std::get<index>(funcTuple));
} }
}, begin, end); }, begin, end);
} }

View file

@ -4,6 +4,8 @@
#include <iostream> #include <iostream>
#include <tuple> #include <tuple>
#include <memory> #include <memory>
#include <unordered_map>
#include <mutex>
#include <EC/Meta/Meta.hpp> #include <EC/Meta/Meta.hpp>
#include <EC/EC.hpp> #include <EC/EC.hpp>
@ -586,22 +588,35 @@ TEST(EC, ForMatchingSignatures)
{ {
EC::Manager<ListComponentsAll, ListTagsAll> manager; EC::Manager<ListComponentsAll, ListTagsAll> manager;
auto e = { std::size_t e[] = {
manager.addEntity(),
manager.addEntity(),
manager.addEntity(),
manager.addEntity(), manager.addEntity(),
manager.addEntity(), manager.addEntity(),
manager.addEntity(), manager.addEntity(),
manager.addEntity() manager.addEntity()
}; };
auto& first = e[0];
auto& last = e[6];
for(auto id : e) for(auto id : e)
{ {
manager.addComponent<C0>(id); if(id != first && id != last)
manager.addComponent<C1>(id); {
manager.addTag<T0>(id); manager.addComponent<C0>(id);
manager.addComponent<C1>(id);
manager.addTag<T0>(id);
auto& c1 = manager.getEntityData<C1>(id); auto& c1 = manager.getEntityData<C1>(id);
c1.vx = 0; c1.vx = 0;
c1.vy = 0; c1.vy = 0;
}
else
{
manager.addComponent<C0>(id);
}
} }
using namespace EC::Meta; using namespace EC::Meta;
@ -630,28 +645,85 @@ TEST(EC, ForMatchingSignatures)
for(auto id : e) for(auto id : e)
{ {
EXPECT_EQ(2, manager.getEntityData<C0>(id).x); if(id != first && id != last)
EXPECT_EQ(2, manager.getEntityData<C0>(id).y); {
EXPECT_EQ(1, manager.getEntityData<C1>(id).vx); EXPECT_EQ(2, manager.getEntityData<C0>(id).x);
EXPECT_EQ(1, manager.getEntityData<C1>(id).vy); EXPECT_EQ(2, manager.getEntityData<C0>(id).y);
EXPECT_EQ(1, manager.getEntityData<C1>(id).vx);
EXPECT_EQ(1, manager.getEntityData<C1>(id).vy);
}
else
{
EXPECT_EQ(1, manager.getEntityData<C0>(id).x);
EXPECT_EQ(1, manager.getEntityData<C0>(id).y);
}
} }
{
std::unordered_map<std::size_t,int> cx;
std::unordered_map<std::size_t,int> cy;
std::unordered_map<std::size_t,int> c0x;
std::unordered_map<std::size_t,int> c0y;
std::unordered_map<std::size_t,int> c1vx;
std::unordered_map<std::size_t,int> c1vy;
std::mutex cxM;
std::mutex cyM;
std::mutex c0xM;
std::mutex c0yM;
std::mutex c1vxM;
std::mutex c1vyM;
manager.forMatchingSignatures< manager.forMatchingSignatures<
TypeList<TypeList<C0>, TypeList<C0, C1> > TypeList<TypeList<C0>, TypeList<C0, C1> >
> >
( (
std::make_tuple( std::make_tuple(
[] (std::size_t eid, C0& c) { [&first, &last, &cx, &cy, &cxM, &cyM] (std::size_t eid, C0& c) {
EXPECT_EQ(2, c.x); if(eid != first && eid != last)
EXPECT_EQ(2, c.y); {
c.x = 5; {
c.y = 7; std::lock_guard<std::mutex> guard(cxM);
cx.insert(std::make_pair(eid, c.x));
}
{
std::lock_guard<std::mutex> guard(cyM);
cy.insert(std::make_pair(eid, c.y));
}
c.x = 5;
c.y = 7;
}
else
{
{
std::lock_guard<std::mutex> guard(cxM);
cx.insert(std::make_pair(eid, c.x));
}
{
std::lock_guard<std::mutex> guard(cyM);
cy.insert(std::make_pair(eid, c.y));
}
c.x = 11;
c.y = 13;
}
}, },
[] (std::size_t eid, C0& c0, C1& c1) { [&c0x, &c0y, &c1vx, &c1vy, &c0xM, &c0yM, &c1vxM, &c1vyM]
EXPECT_EQ(5, c0.x); (std::size_t eid, C0& c0, C1& c1) {
EXPECT_EQ(7, c0.y); {
EXPECT_EQ(1, c1.vx); std::lock_guard<std::mutex> guard(c0xM);
EXPECT_EQ(1, c1.vy); c0x.insert(std::make_pair(eid, c0.x));
}
{
std::lock_guard<std::mutex> guard(c0yM);
c0y.insert(std::make_pair(eid, c0.y));
}
{
std::lock_guard<std::mutex> guard(c1vxM);
c1vx.insert(std::make_pair(eid, c1.vx));
}
{
std::lock_guard<std::mutex> guard(c1vyM);
c1vy.insert(std::make_pair(eid, c1.vy));
}
c1.vx += c0.x; c1.vx += c0.x;
c1.vy += c0.y; c1.vy += c0.y;
@ -661,13 +733,61 @@ TEST(EC, ForMatchingSignatures)
}), }),
3 3
); );
for(auto iter = cx.begin(); iter != cx.end(); ++iter)
{
if(iter->first != first && iter->first != last)
{
EXPECT_EQ(2, iter->second);
}
else
{
EXPECT_EQ(1, iter->second);
}
}
for(auto iter = cy.begin(); iter != cy.end(); ++iter)
{
if(iter->first != first && iter->first != last)
{
EXPECT_EQ(2, iter->second);
}
else
{
EXPECT_EQ(1, iter->second);
}
}
for(auto iter = c0x.begin(); iter != c0x.end(); ++iter)
{
EXPECT_EQ(5, iter->second);
}
for(auto iter = c0y.begin(); iter != c0y.end(); ++iter)
{
EXPECT_EQ(7, iter->second);
}
for(auto iter = c1vx.begin(); iter != c1vx.end(); ++iter)
{
EXPECT_EQ(1, iter->second);
}
for(auto iter = c1vy.begin(); iter != c1vy.end(); ++iter)
{
EXPECT_EQ(1, iter->second);
}
}
for(auto eid : e) for(auto eid : e)
{ {
EXPECT_EQ(1, manager.getEntityData<C0>(eid).x); if(eid != first && eid != last)
EXPECT_EQ(2, manager.getEntityData<C0>(eid).y); {
EXPECT_EQ(6, manager.getEntityData<C1>(eid).vx); EXPECT_EQ(1, manager.getEntityData<C0>(eid).x);
EXPECT_EQ(8, manager.getEntityData<C1>(eid).vy); EXPECT_EQ(2, manager.getEntityData<C0>(eid).y);
EXPECT_EQ(6, manager.getEntityData<C1>(eid).vx);
EXPECT_EQ(8, manager.getEntityData<C1>(eid).vy);
}
else
{
EXPECT_EQ(11, manager.getEntityData<C0>(eid).x);
EXPECT_EQ(13, manager.getEntityData<C0>(eid).y);
}
} }
} }