Boost logo

Boost Users :

From: ajb_at_[hidden]
Date: 2005-06-01 20:22:11


G'day all.

"Sliwa, Przemyslaw (London)" <Przemyslaw_Sliwa_at_[hidden]> wrote:

> I have a question which is not related directly to boost.
> I am writing a multithreaded application and would like to make use of
> a multiprocessor machine in order to speed up our Monte Carlo
> simulation engine. We make use of the random number package (random
> number distributions). My question is: making the random number
> generator a global variable (object) it is possible to use it in
> several threads at the same time -> does it mean that the random
> sequences will be repeated and the entire simulation will be simply a
> repetition of n non-random sequences? This can be avoided when a lock
> is acquired on the random number generator and at a given time just
> one thread can access the rng and the advantage of the multiprocessor
> machine is lost. Can you advise?

You might be able to ease the pain by requesting them from the RNG in
blocks and caching them in a thread-local way. The attached code is
untested, but it should give you a general idea. You create a
concurrent_number_generator_adaptor for the RNG, then create a
number_generator_cache for each thread.

Cheers,
Andrew Bromage
--------8<---CUT HERE---8<--------

template<class Generator>
class concurrent_number_generator_adaptor
{
public:
    // This class models NumberGenerator, in addition to a get_bulk
    // operation which gets a bunch of numbers. (This should probably
    // be modelled as a concept in its own right.)

    BOOST_CLASS_REQUIRE(Generator, boost, NumberGeneratorConcept);

    typedef Generator generator_type;
    typedef typename Generator::result_type result_type;

    result_type
    operator()()
    {
        Generator& gen = *gen_;
        mutex::scoped_lock lck(mut_);
        return gen();
    }

    template<typename It>
    void
    get_bulk(int num, It out)
    {
        function_requires< OutputIteratorConcept<It> >();

        Generator& gen = *gen_;
        mutex::scoped_lock lck(mut_);
        while (num-- > 0)
        {
            *out++ = gen();
        }
    }

    concurrent_number_generator_adaptor(const shared_ptr<Generator> gen)
        : gen_(gen)
    {
    }

private:
    mutex mut_;
    shared_ptr<Generator> gen_;
};

template<class Generator, int N>
class number_generator_cache
{
public:
    // This class models NumberGenerator

    BOOST_CLASS_REQUIRE(Generator, boost, NumberGeneratorConcept);
    // We also require the get_bulk() operation.

    typedef Generator generator_type;
    typedef typename Generator::result_type result_type;

    result_type
    operator()()
    {
        if (pos_ == cache_.end())
        {
            gen_->get_bulk(N, cache_);
            pos_ = cache_.begin();
        }

        return *pos_++;
    }

    number_generator_cache(const shared_ptr<Generator> gen)
        : gen_(gen), pos_(cache_.end())
    {
    }

private:
    typedef array<result_type,N> cache_type;
    shared_ptr<Generator> gen_;
    cache_type cache_;
    cache_type::iterator pos_;
};


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