Boost logo

Boost :

Subject: Re: [boost] [uuids] generating uuids from multiple threads
From: Andy Tompkins (atompkins_at_[hidden])
Date: 2009-01-09 16:46:29


On Fri, 09 Jan 2009 12:46:20 -0600, "Michael Marcin"
<mike.marcin_at_[hidden]> said:
> Edouard A. wrote:
> >
> > On Fri, 09 Jan 2009 03:48:05 -0600, Michael Marcin
> > <mike.marcin_at_[hidden]> wrote:
> >
> >> For one thing this is yet another case where I used a default
> >> constructor on a uuid during natural coding and expected it to be
> >> cheap but I digress.
> >>
> >> Do I have to protect the shared generator with a mutex? Should I
> >> even be using a shared generator or should I be constructing it on
> >> the stack in this function? I don't expect this to be called very
> >> often (twice total in our current application) but I want to make
> >> sure it is bullet proof since it can potentially be called
> >> concurrently.
> >
> > A PRNG is stateful, hence concurrent access lead need to be
> > protected, but your mutex needs to be static, of course.

This is true. Thus a boost::uuids::uuid_generator is not thread safe
and must be protected from concurrent access.

> > I just had exactly the same need and I did protect it with a
> > mutex. You will probably also have the need to do a "init once"
> > for your PRNG.
> >
> > I did something like this for the init :
> >
> > static boost::hellekalek1995 rng; static boost::mutex mutex;
> > static volatile bool initialized = false;
> >
> > if (!initialized) { // double checking pattern
> > boost::lock_guard<boost::mutex> lock(mutex); if
> > (!initialized) { // do the init
> > rng.seed(blah blah blah); initialized = true;
> > } }
> >
>
> I'm not a threading guru but I was under the impression that double-
> checked locking pattern is dependent on the compiler and processor
> memory model and not portable.
>
> I am guaranteed that my function won't be called before main and no
> threads are started before main so I think that gives me some leeway
> for an easier solution.
>
> The uuids documentation says:
>
> "The boost::uuids::uuid_generator::operator() function returns a random-number-
> based uuid. The default random number generator is boost::mt19937 from
> the Boost Random library. It is seeded with a SHA-1 hash of a number
> of different values including std::time(0), std::clock(),
> uninitialized data, value return from new unsigned int, etc.."
>
> I'm not sure if this means I can expect to create a uuid_generator on
> the stack and get a uuid A and then create a uuid_generator on the
> stack and get uuid A != B. It seems to be that if somehow thread id or
> processor id was also used to create the seed the value I could do
> this and avoid any shared state and locking.

It is expensive to create a boost::uuids::uuid_generator compared to
generating a uuid from it. If you are creating lots of them, you may
not want to create a generator every time you need to create a uuid.

You can expect that different uuid_generators will produce different
uuids, but it is possible that they will not. This is not likely
since it is likely that they will be seeded with different seeds.
This could be a good solution for you, that is create one
uuid_generator per thread.

> --
> Michael Marcin

Regards,
  Andy


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk