2017-02-10 5 views
13

У меня есть некоторый код, который выглядит как это:безопасности Нить станд :: random_device

std::random_device rd; 

#pragma omp parallel 
{ 
    std::mt19937 gen(rd()); 
    #pragma omp for 
    for(int i=0; i < N; i++) 
    { 
     /* Do stuff with random numbers from gen() */ 
    } 
} 

У меня есть несколько вопросов:

  • Is std::random_device поточно? Т.е. он собирается делать что-то бесполезное, когда сразу несколько потоков называют его?
  • Это вообще хорошая идея? Должен ли я беспокоиться о перекрывающихся потоках случайных чисел?
  • Есть ли лучший способ достичь того, что я хочу (независимые потоки случайных чисел в каждом потоке - я не слишком беспокоюсь о воспроизводимости на данный момент)?

В случае никакого значения для выработок std::random_device я в первую очередь работает на Windows, хотя я хотел бы код, чтобы одинаково хорошо работать на Linux и OSX, а также.

+0

Вы можете добиться воспроизводимости, но используя конкретное семя, а не используя 'std :: random_device'. – Galik

+0

'random_device' скорее всего будет блокировать. Если вам нужен параллелизм, нет смысла использовать его таким образом. Вы можете использовать глобальный PRNG, засеянный с помощью 'random_device', для семени' mt19937' (но для этого потребуется явная блокировка). – sbabbi

ответ

3

Примечание: Этот ответ работает на GCC Linux но OpenMP вообще не гарантируется между оперируют std потоковая модель, так как особенности thread_local может не работать.

(удалит этот ответ, если это позволит мне)

я бы, вероятно, сделать PRNG поток локального статического и инициализировать его с временным std::random_device:

#pragma omp parallel 
{ 
    // different gen for each thread 
    thread_local static std::mt19937 gen(std::random_device{}()); 
    #pragma omp for 
    for(int i=0; i < N; i++) 
    { 
     /* Do stuff with random numbers from gen() */ 
    } 
} 

Это даст вам ровно один std::mt19937 за поток и сэкономить время на их построение с помощью нескольких вызовов функции.

+1

Спасибо, я не знал ключевое слово 'thread_local'. В более общем плане, когда я делаю этот стиль с параллельными областями openmp, должен ли я использовать 'thread_local', чтобы сделать вещи правильными нитями локальными? Я думал, что достаточно просто указать переменную внутри параллельной области? – Theolodus

+0

@ Theolodus На самом деле да, вы правы, находясь в параллельном регионе, он уже делает его конкретным. Я полагаю, что отвлечение внимания на это заключается в том, что, будучи конкретным потоком, можно сделать «статическим», давая потенциальную производительность, если функция вызывается часто, и генератор может быть инициализирован временным, не платя за создание временного более одного раза (за thread) – Galik

+0

Вы уверены, что '#pragma omp' полностью соответствует поточной модели C++ 11? Местные жители нитей гарантированно работают в потоке 'std', но для их работы в других системах потоковой передачи вам требуются гарантии от авторов этой системы потоков ... – Yakk