2121
2222#include < chrono>
2323#include < cstdint>
24- #include < stdexcept>
2524#include < random>
26- #include < thread>
25+ #include < boost/ thread.hpp >
2726#include < bitcoin/bitcoin/utility/asio.hpp>
28- #include < bitcoin/bitcoin/utility/assert.hpp>
2927#include < bitcoin/bitcoin/utility/data.hpp>
28+ #include < bitcoin/bitcoin/utility/thread.hpp>
3029#include < bitcoin/bitcoin/constants.hpp>
3130
3231namespace libbitcoin {
32+
33+ using namespace bc ::asio;
34+ using namespace std ::chrono;
3335
3436// DO NOT USE srand() and rand() on MSVC as srand must be called per thread.
3537// Values may be truly random depending on the underlying device.
36- // TODO: convert pseudo_random/nonzero_pseudo_random methods to templates.
3738
38- uint64_t pseudo_random ()
39+ static uint32_t get_clock_seed ()
3940{
40- return pseudo_random (0 , max_uint64);
41+ const auto now = high_resolution_clock::now ();
42+ return static_cast <uint32_t >(now.time_since_epoch ().count ());
4143}
4244
43- uint64_t pseudo_random ( uint64_t begin, uint64_t end )
45+ static std::mt19937& get_twister ( )
4446{
45- std::uniform_int_distribution<uint64_t > distribution (begin, end);
46- std::random_device device;
47- return distribution (device);
47+ // Boost.thread will clean up the thread statics using this function.
48+ const auto deleter = [](std::mt19937* twister)
49+ {
50+ delete twister;
51+ };
52+
53+ // Maintain thread static state space.
54+ static boost::thread_specific_ptr<std::mt19937> twister (deleter);
55+
56+ // This is thread safe because the instance is static.
57+ if (twister.get () == nullptr )
58+ {
59+ // Seed with high resolution clock.
60+ twister.reset (new std::mt19937 (get_clock_seed ()));
61+ }
62+
63+ return *twister;
4864}
4965
50- uint64_t nonzero_pseudo_random ()
66+ uint64_t pseudo_random ()
5167{
52- return pseudo_random (1 , max_uint64);
68+ return pseudo_random (0 , max_uint64);
5369}
5470
55- uint64_t nonzero_pseudo_random ( uint64_t end)
71+ uint64_t pseudo_random ( uint64_t begin, uint64_t end)
5672{
57- return pseudo_random (1 , end);
73+ std::uniform_int_distribution<uint64_t > distribution (begin, end);
74+ return distribution (get_twister ());
5875}
5976
6077void pseudo_random_fill (data_chunk& chunk)
6178{
6279 // uniform_int_distribution is undefined for sizes < 16 bits.
6380 std::uniform_int_distribution<uint16_t > distribution (0 , max_uint8);
64- std::random_device device;
6581
6682 for (auto & byte: chunk)
67- byte = static_cast <uint8_t >(distribution (device ));
83+ byte = static_cast <uint8_t >(distribution (get_twister () ));
6884}
6985
7086// Randomly select a time duration in the range:
@@ -73,9 +89,6 @@ void pseudo_random_fill(data_chunk& chunk)
7389asio::duration pseudo_randomize (const asio::duration& expiration,
7490 uint8_t ratio)
7591{
76- using namespace bc ::asio;
77- using namespace std ::chrono;
78-
7992 if (ratio == 0 )
8093 return expiration;
8194
0 commit comments