May I use MersenneTwister as I want ? - Printable Version +- Cuberite Forum (https://forum.cuberite.org) +-- Forum: Cuberite (https://forum.cuberite.org/forum-4.html) +--- Forum: Development (https://forum.cuberite.org/forum-13.html) +--- Thread: May I use MersenneTwister as I want ? (/thread-1174.html) |
May I use MersenneTwister as I want ? - mgueydan - 07-04-2013 Hi. I can see you are using a very specific random function, that is not thread-safe, and maybe heavy to load. I didn't read the whole class, just the comments, and they are frightening. Question are : 1. may I instanciate one where and when I want ? 2. may I instanciate a static one ? If this is touchy (aka I cannot instantiate one where I want), I'll suggest to refactor it's usage, for example through something like a std::map<thread,MTRand> that would be accessed statically. What would you think about it ? Basically : it would not be coder-friendly to have to think twice for getting a random number. But maybe it's all in my head. Thanks RE: May I use MersenneTwister as I want ? - xoft - 07-04-2013 Basically, you are right. 1, Yes, you can, but as you've already noted, it's quite some heavy-lifting to do so. If you can work around it, go around it. 2, Yes, you can, theoretically, as long as you can guarantee a single thread accessing it at a time (locking etc). For these reasons, there is an MTRand instance within cWorld that is to be used in the Tick thread exclusively and has some accessor functions in cWorld directly (GetTickRandomNumber() ). If you can guarantee that your function runs only in the tick thread, you can use it. Usually, we don't even need such a big random function; if you just need a reasonably random number, you could use the cNoise IntNoiseNDInt() functions, feeding them some clock-based values, such as the number of ticks elapsed in the world, world seed, and probably some kind of a static counter. Another question is, how does MTRand fail when used in multiple threads? Does the failure produce crashes, or does it simply just somewhat degrade the resulting random numbers? If the latter, I'd personally go with abusing that and simply using it from multiple threads. RE: May I use MersenneTwister as I want ? - mgueydan - 07-04-2013 (07-04-2013, 01:58 AM)xoft Wrote: For these reasons, there is an MTRand instance within cWorld that is to be used in the Tick thread exclusively and has some accessor functions in cWorld directly (GetTickRandomNumber() ). If you can guarantee that your function runs only in the tick thread, you can use it. This is a the bad architecture point I was refering to : You don't want the code you are writing being good or bad depending on the way it will be used later. If you do that, you'll have bugs inside a long-time written code, just because you changed something almost un related that is using it deep inside. My case is the method cEntityManager::NewMonsterFromType I'm currently implementing. I'm not sure, right now, where it will be used. I just know that, for now, it will only be used inside cWorld::tick. If tomorrow we decide to use it from the world generation (to randomly spawn bunch of mobs at start for instance), it will no longer comply the "only tick" or the "single tread" rule. What we need is stop instanciating MTRand inside our code, but rather do it in an encapsulation of this type : http://docs.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html (sorry it's Java). would you agree on the idea to include this refactoring on the roadmap at some point ? Or am I wrong somewhere ? RE: May I use MersenneTwister as I want ? - xoft - 07-04-2013 We don't have a thread-local storage, so you'd need to implement one - not a trivial task, considering all the platforms we support. Also, you need some kind of management for when a new thread is created or another one ends, to create and destroy the objects. Next, you have performance issues - will it be fast enough to be called as many times as required? And if the result contains any synchronization primitive, how much will it be susceptible to deadlocks? Two easier solutions: - let the caller provide a random number; the caller knows which thread it's on and can therefore decide on TickRand or a different generator - use a different generator. I still think using cNoise would be the best bet here. |