registry, dispatcher and emitter (as far as I remember) use internal indexes during an assure.
They work just fine across boundaries and eg with multiple registries on a single thread, put aside the possibility of re-indexing that could be annoying but isn't a problem anyway. On the other hand, when eg multiple registries with different collections of types are used concurrently from multiple threads, re-indexing may cause problems.
A possible solution is to adapt the old fashioned sequential generators and use it in these cases.
Another valid approach is that of using linear probing and fully get rid of internal indexes. This is probably the best solution, since it's also more dll-friendly apparently.
Hi, sorry to come here out of the blue but I encountered a problem that seems related to this one.
I'm using multiple entt registries in different threads, the threads are totally isolated.
I work on population-based heuristic optimizers, I need to launch them 100 to 1000 times with different initial random states.
Context:
I need to launch such batches for many configurations (order 1e6) and the run time for each configuration is so small that the overhead of launching processes from (eg. python) scripts is huge.
Let's not even talk about outputting data to that much files.
Hence, the c++ population simulation code integrates a pool of N threads wich shares the different isolated instance of the same program with different random states.
I encountered a really strange bug where I extremely rarely get a segfault because an entity does not 'exist'. Only happens when threading is on.
The quick fix I found, wich is only applicable to isolated threaded registries is to make some of the static internal indexes thread_local. I am coming back to the project, I want to see if everything behaves correctly this way.
I would like to be more precise but It's been a while since I came across this bug. I you need more information, to build tests, feel free to ask.
@Kaeryv
Hello!
@skypjack is working on a solution. For the time being, you could apply a simple patch to EnTT: add thread_local storage specifier to index variable in the registry::assure function.
Yup @Kaeryv most likely you're hitting this issue.
As @Innokentiy-Alaytsev pointed out, thread_local is a workaround as well as using one of the previous versions.
Unfortunately, I completely missed this case. My fault. I'm working on the patch but the quarantine is slowing things down a bit.
Thanks for the amazing work. I'll go on with the quick fix until the patch is ready.
I hope you're all safe.
I'm running into what might be the same problem. Here's an MCVE:
#include <future>
#include <vector>
#include <entt/entt.hpp>
struct TypeA
{
};
struct TypeB
{
};
void do_nothing(entt::registry &, entt::entity) {}
int main()
{
std::vector<std::future<void>> futures;
for (int i = 0; i < 1000; i++)
{
futures.emplace_back(std::async(std::launch::async, [] {
entt::registry registry;
registry.on_destroy<TypeA>().connect<do_nothing>();
for (int j = 0; j < 1000; j++)
{
const auto entity = registry.create();
registry.assign<TypeB>(entity);
}
}));
}
for (auto &future : futures)
{
future.get();
}
}
It only crashes when I add the on_destroy observer, is that expected?
It may be, yeah. Likely I'll push a patch during the weekend or early next week. Then we will be able to test also this case.
Thank you very much for investing your time in an MCVE. :+1:
I pushed some changes to experimental and updated the documentation and the tests accordingly.
I'll close this one soon but feel free to drop a line or to reopen it if the problem persists. :+1:
My tests pass now. Seems to be fixed.
Upstream on master. I'm closing the issue. Thank you guys for your help. :+1:
Most helpful comment
My tests pass now. Seems to be fixed.