Подтвердить что ты не робот

Является ли random_shuffle потокобезопасным? и используя rand_r, если это не

Является std:: random_shuffle threadsafe? Я полагаю, что нет, поскольку регулярный rand() не является потокобезопасным. Если это так, то как бы я использовал rand_r со случайным_характом, чтобы я мог дать каждому потоку уникальное семя. Я видел примеры использования пользовательских случайных генераторов с random_shuffle, но мне все еще не ясно.

Спасибо.

4b9b3361

Ответ 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());