Boost logo

Boost Users :

Subject: Re: [Boost-users] [random] Singleton engine
From: Kevin Martin (kev82_at_[hidden])
Date: 2009-08-04 12:10:14


On 4 Aug 2009, at 06:39, Diederick C. Niehorster wrote:

>
> I have the following requirements:
>
> 1) only one generator may exist (hence the singleton), it does not
> matter whether this generator is constructed at program start or first
> use. I do not forsee ever using another generator.

Ok, I guess our requirements are very different. I don't understand
why you would need to force there to only ever be one instance,
certainly not to the extent where you go and write code to enforce it.

> 2) generator is seeded upon construction.

But where does this happen, with your design it is not always
guaranteed to be in the same place.

> Once seeded, for further
> calls to the generator instance providing a seed, that seed should be
> ignored/the generator should not be reseeded. This is what my code
> currently does

Is repeatability of experiments not an issue for you? If you want to
repeat runs then you need to know what the seed value is before you
start drawing numbers from the generator, and you also need to be able
to set it before any numbers are drawn. At what point do you set the
seed?

> 3) Right now, i do not forsee the need of generating random numbers
> before main has been called. However, I am interested in knowing what
> the problem would be in trying to use my class before main has been
> called, I have never dealt with such problems and would appreciate a
> kick in the right direction so I can learn something about it.

What I was trying to get at is that if you are intending to seed the
generator with a specific value, then this can't really happen until
main(). However if you have a global object whose constructor draws
some numbers from the generator, then it will do so before the seed is
set, this is clearly bad.

> 4) will not be used in multithreaded environment. If it ever would be,
> I would like all threads to use the same generator instance. Is that
> what will happen now? (I know I would then also have to worry about
> race conditions, but lets not get into that now).

The multithreaded problem is a real pain, the issue once again is
repeatability. If thread A and B are both requesting a number, then
there is no deterministic guarantee about which thread will manage to
lock the appropriate mutex first, and so over multiple executions, the
same threads will not get the same numbers.

>
> I have looked it up, thank you for the suggestion. I, however do not
> see the advantage of wrapping the generator.

Well you are wrapping up the variate_generator yourself with your
specializations of the CRandom template. My suggestion is that instead
of your CRandom class, you just return the variate_generator inside a
boost function.

> Also, how does your
> approach assure that the same engine is always used and that this
> enigine is never destructed once constructed before program end

The shared_ptr is a static variable in an object file, it is only
accessible by functions. The set function will only allow it to be set
once. A reference to the generator is obtained by calling a global
function and it will always return the same thing (assuming it has
been allocated). Destruction will occur whenever the operating system
destroys global objects. I have no idea when that is, and it is most
likely very platform dependent, however it will always be long after
main has returned.

> (i see
> you are using a shared pointer, I assume it would destruct the engine
> when all references went out of scope)?

There should only ever be two shared_ptrs point to the generator, the
first is the one that holds the instance I create, the second is the
static global variable. Whenever I create a variate_generator, it does
NOT pass any shared_ptrs around or alter any reference counts, it just
passes the address of the actual generator. That's because I know the
global variable will keep the generator in scope for all the time that
I am in main() and thus the entre scope of the variate_generator.

> I now have a compact class
> that also ensures i cannot forget to seed my engine as that is done in
> the constructor.

Does it make sure you can't forget to seed it, or does it
automatically seed it with time(), there is a difference.

>
> I just tested this, and Instance() and Instance(unsigned int) indeed
> return different objects (different memory address), so this is an
> issue. How do I get around this, I want only one instance of
> boost::mt19937 to be instantiated, no matter whether any argument or
> what type of argument is supplied to Instance(). Should i use a Gamma
> Singleton for that (if (!m_pInstance) m_pInstance=new T; return
> *m_pInstance;)?

Sorry, I don't know what a Gamma Singleton is, if you haven't gathered
yet I'm a little anti-singleton. I think it's a far too overused, not
particularly useful pattern.

To solve this issue you need the object that is the focus of the
singleton to only exist in one place. Off the top of my head I would
suggest a static class variable which points to the object in question.

Thanks,
Kevin Martin



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net