Как посеять случайные в разных темах

У меня есть многопоточное приложение C ++, которому нужно много случайных чисел в каждом потоке.

До C ++ 11 я использовал «randomizer», который генерирует некоторые случайности в основном потоке с rand() функция, и он передает разные случайности для каждой подпотока. Затем все подпотоки присоединяются к основному потоку, снова используется рандомизатор, и вызываются новые подпотоки и так далее для N раз.

Теперь я хотел бы заменить rand() с C ++ 11, чтобы избежать рандомизатора и генерировать случайные числа в каждом потоке.

Я хотел бы запустить генератор случайных чисел так, чтобы:
* последовательность семян изменяется от бега к бегу
* последовательность случайных чисел в каждом потоке отличается от потока к потоку (также, если поток вызывается в разных циклах)

Я думал, что посева так:

mt19937 rng;
rng.seed(this_thread::get_id().hash());

что хорошо для меня с тех пор this_thread::get_id().hash() это «случайное» число, но иногда в разных циклах я мог получить одинаковые идентификаторы.

Как я мог бы запустить случайным образом генератор случайных чисел, чтобы избежать получения одинаковой последовательности случайных чисел в некоторых потоках?

1

Решение

Поскольку идентификаторы потоков отличаются, возможно, просто увеличьте значения с помощью часов:

#include <chrono>
...

typedef std::m19937::result_type seed_type;

typename std::chrono::system_clock seed_clock;
auto init_seed = static_cast<seed_type>
(seed_clock.now().time_since_epoch().count());

init_seed += static_cast<seed_type>(this_thread::get_id());

rng.seed(init_seed);
2

Другие решения

Соответствующее значение по умолчанию для посева:

std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 eng(seed);

Вы можете просто сделать это в каждом потоке, и это должно работать:

#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <mutex>
#include <random>
#include <thread>

int main() {
std::mutex iomutex;

std::vector<std::thread> threads;

for (int i = 0 ; i < 10; ++i) {
threads.emplace_back([&iomutex](int tid) {
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};

std::mt19937 eng(seed);
std::uniform_int_distribution<> dist(1, 100);

std::lock_guard<std::mutex> ioguard(iomutex);
std::cout << "Thread " << tid << ": ";
std::generate_n(std::ostream_iterator<int>(std::cout, " "), 10, std::bind(dist, eng));
std::cout << '\n';
}, i);

}
for (auto &&t : threads) {
t.join();
}
}

В качестве альтернативы вы можете вычислить начальные значения в главном потоке и передать каждому рабочему данные для инициализации своего механизма. К сожалению, вы не можете пройти seed_seq, поэтому в приведенном ниже примере я просто пропускаю инициализированный движок.

int main() {
std::mutex iomutex;
std::vector<std::thread> threads;
std::random_device r;

for (int i = 0 ; i < 10; ++i) {
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 thread_eng(seed);

threads.emplace_back([&iomutex](int tid, std::mt19937 init_eng) {
std::mt19937 eng(std::move(init_eng));
std::uniform_int_distribution<> dist(1, 100);

std::lock_guard<std::mutex> ioguard(iomutex);
std::cout << "Thread " << tid << ": ";
std::generate_n(std::ostream_iterator<int>(std::cout, " "), 10, std::bind(dist, eng));
std::cout << '\n';
}, i, thread_eng);

}
for (auto &&t : threads) {
t.join();
}
}
1

По вопросам рекламы [email protected]