Является ли random_shuffle потокобезопасным? и используя rand_r, если это не так
Является ли std::random_shuffle потокобезопасным? Я полагаю, нет, так как обычный rand() не является потокобезопасным. Если это так, как бы я использовал rand_r с random_shuffle, чтобы я мог дать каждому потоку уникальное начальное число. Я видел примеры использования пользовательских генераторов случайных чисел с random_shuffle, но мне все еще неясно.
Благодарю.
3 ответа
Использовать 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));
Вам необходимо предоставить функцию генератора случайных чисел или объект-функтор, который принимает тип целочисленного значения и возвращает другое значение некоторого целочисленного типа, которое не будет выходить за границы контейнера, через который проходят итераторы, которые вы передали в функцию. Также в случае объекта функтора он должен реализовывать 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
,
Возможно нет.
Используйте вторую версию 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());