Является ли random_shuffle потокобезопасным? и используя rand_r, если это не
Является std:: random_shuffle threadsafe? Я полагаю, что нет, поскольку регулярный rand() не является потокобезопасным. Если это так, то как бы я использовал rand_r со случайным_характом, чтобы я мог дать каждому потоку уникальное семя. Я видел примеры использования пользовательских случайных генераторов с random_shuffle, но мне все еще не ясно.
Спасибо.
Ответы
Ответ 1
Чтобы использовать rand_r
с std::random_shuffle
, вам нужно написать (довольно тривиальную) оболочку. Генератор случайных чисел, который вы передаете в random_shuffle
, должен принять параметр, который задает диапазон чисел, которые будут созданы, а rand_r
- нет.
Ваша обложка будет выглядеть примерно так:
class rand_x {
unsigned int seed;
public:
rand_x(int init) : seed(init) {}
int operator()(int limit) {
int divisor = RAND_MAX/(limit+1);
int retval;
do {
retval = rand_r(&seed) / divisor;
} while (retval > limit);
return retval;
}
};
Вы использовали бы его с random_shuffle
что-то вроде:
std::random_shuffle(whatever.begin(), whatever.end(), rand_x(some_seed));
Ответ 2
Вам необходимо предоставить функцию генератора случайных чисел или объект-функтор, который принимает целочисленный тип значения и возвращает другое значение некоторого целочисленного типа, который не будет переполнять границы контейнера, которые итераторы, которые вы передали в функцию, повторяются через. Также в случае объекта-функтора он должен реализовать operator()
, чтобы его можно было вызвать как функцию. Поскольку вам нужен поточно-безопасный генератор случайных чисел, использование srand
и rand
из cstdlib
- плохая идея... вместо этого вы должны создать некоторый объект-функтор, который реализует поточно-безопасный генератор случайных чисел или генератор случайных чисел, который не реализует глобально доступные переменные, так что все остается локальным хранилищем.
Так, например, один из способов, которым это могло бы работать, - у вас есть какой-то генератор случайных чисел, который вы получили из другой библиотеки, которая будет генерировать только случайные значения между фиксированным диапазоном значений, чтобы вы могли определить границы контейнера для Итераторы с произвольным доступом используют алгоритм random_shuffle
. Теперь, в зависимости от используемой библиотеки, функтор может выглядеть примерно так:
class my_rand_gen
{
private:
random_gen_type random_range_gen;
int min;
int max;
public:
my_rand_gen(const random_gen_type& gen, int min_range, int max_range):
random_range_gen(gen), min(min_range), max(max_range) {}
int operator()(int value)
{
//ignore the input value and use our own defined range
//returns a value between min and max
return random_range_gen(min, max);
}
};
Теперь вы можете вызвать алгоритм следующим образом:
random_shuffle(my_vector_start_iter, my_vector_end_iter,
my_rand_gen(rand_generator_lib,
vector_start_index,
vector_end_index));
и он будет перемешать вектор между стартовым и конечным итераторами на ваш вектор без переполнения границ вектора... другими словами, он будет использовать только значения для тасования между vector_start_index
и vector_end_index
.
Ответ 3
Возможно, нет.
Используйте вторую версию adnrom_shuffle, которая принимает параметр шаблона для генератора случайных чисел: http://www.sgi.com/tech/stl/random_shuffle.html. Генератор должен соответствовать: http://www.sgi.com/tech/stl/RandomNumberGenerator.html
struct MyRandomNumberGenerator
{
int operator()(int limit) const
{
// get threadsafe random number
}
};
// Stuff
random_shuffle(list.begin(), list.end(), MyRandomNumberGenerator());