Как известно, boost::random не является thread safe.
Тогда если глобально есть
boost::random::mt19937 gen(42);
И из разных потоков одновременно очень часто вызывать
uint32_t randVal = gen();
то что может произойти?
Я вижу 2 опасности:
1) Для одновременных вызовов всегда будут сгенерированы одинаковые значения;
2) Произойдет undefined behaviour и вызов либо "зависнет", либо вывалится с segmentation fault.
Моя задача — с максимальной производительностью получать псевдо-случайные числа от gen.min() до gen.max(), качество чисел не важно. Поэтому без нужны закрывать мьютексом не хотелось бы.
Здравствуйте, prrt, Вы писали:
P>Моя задача — с максимальной производительностью получать псевдо-случайные числа от gen.min() до gen.max(), качество чисел не важно. Поэтому без нужны закрывать мьютексом не хотелось бы.
Что мешает просто иметь в каждом потоке свой генератор? Просто добавь ключевое слове thread_local:
thread_local boost::random::mt19937 gen;
Ну и по желанию инициализируй эти генераторы не константой, а комбинацией из времени и номера потока.
Здравствуйте, MTD, Вы писали:
MTD>Максимально быстро — иметь в каждом потоке свой генератор.
В каждом потоке свой генератор далеко не очевидно, как сделать. Потоки — это boost::thread из асинхронного http сервера boost::asio. Свой генератор для каждого Connection — это легко, но смысла в данном случае не имеет (большое число соединений, в т.ч. короткоживущих).
Здравствуйте, prrt, Вы писали:
P>В каждом потоке свой генератор далеко не очевидно, как сделать.
А в чем сложность? Пишешь примерно так:
auto gen = RandomGenerator();
И используешь.
P>Потоки — это boost::thread из асинхронного http сервера boost::asio.
К чему тогда разговоры про максимально быстро? Делай как хочешь, генератор случайных чисел будет последнее что надо оптимизировать.
P>Свой генератор для каждого Connection — это легко, но смысла в данном случае не имеет (большое число соединений, в т.ч. короткоживущих).
И что? Если они короткоживущие, то любой конект убъет все твои оптимизации. Да и для keep-alive соединений генератор случайных чисел будет последнее что надо оптимизировать.
Понимаешь, точка синхронизации, даже неявная в виде, например, shared_ptr переданного по значению приводит к тому, что твои потоки и ядра процессора начинают простаивать. Перед тем как синхронизировать потоки надо 2 раза подумать, а надо ли?
Здравствуйте, MTD, Вы писали:
MTD>Здравствуйте, watchmaker, Вы писали:
W>>Просто добавь ключевое слове thread_local:
MTD>Это еще зачем? Просто создать новый объект уже не модно?
Здравствуйте, watchmaker, Вы писали:
W>Просто добавь ключевое слове thread_local: W>
thread_local boost::random::mt19937 gen;
Да, это, похоже, то, что нужно. Только вот компилятор старый, thread_local не поддерживает. Поковырялся с boost::thread_specific_ptr, не вышло, или ошибки при компиляции, или на этапе выполнения.
В итоге сделал пока так:
Глобально
Здравствуйте, prrt, Вы писали:
P>Моя задача — с максимальной производительностью получать псевдо-случайные числа от gen.min() до gen.max(), качество чисел не важно. Поэтому без нужны закрывать мьютексом не хотелось бы.
Делаешь пул из десятка генераторов. Сид каждого генератора инициализируешь его номером в пуле. Каждый генератор в пуле защищаешь мьютексом. В нитках используешь генератор под номером thread_id % 10. Так вероятность коллизий будет маленьклй.