2016-11-16 4 views
0

내가 스레드 안전 기능스레드 안전 병렬 RNG()

rand_r 

와 파이의 계산이 버전을 사용하지만이를 실행할 때 느린 것 같습니다 (그리고 대답은 잘못된 것입니다) 프로그램은 병렬 처리 프로그램과 비교하여 순차 프로그램과 비교하여 스레드 안전성을 보장하지 못한다. 이 사용 방법은 스레드로부터 안전하지 않은 것으로 보입니다. 그러나 나는 thread-safe PRNG에 관한 많은 질문을 읽고 rand_r이 충분히 안전해야한다는 것을 배웠기 때문에 그 이유를 알지 못합니다.

#include <iostream> 
#include <random> 
#include <ctime> 
#include "omp.h" 
#include <stdlib.h> 

using namespace std; 

unsigned seed; 

int main() 
{ 
double start = time(0); 

int i, n, N; 
double x, y; 



N = 1<<30; 
n = 0; 

double pi; 



#pragma omp threadprivate(seed) 
#pragma omp parallel private(x, y) reduction(+:n) 
{ 

for (i = 0; i < N; i++) { 
seed = 25234 + 17 * omp_get_thread_num(); 
    x = rand_r(&seed)/(double) RAND_MAX; 
    y = rand_r(&seed)/(double) RAND_MAX; 

    if (x*x + y*y <= 1) 
     n++; 
} 
} 

pi = 4. * n/(double) (N); 

cout << pi << endl; 

double stop = time(0); 

cout << (stop - start) << endl; 

return 0; 
} 

P. 그건 그렇고, 마법의 숫자는 무엇입니까

seed = 25234 + 17 * omp_get_thread_num(); 

? 나는 그 (것)들을 어떤 대답에서 훔쳤다.

편집 : Gilles의 의견은 나를 도왔습니다. 해결 방법은 다음과 같습니다. 1. for 루프 및 시드 초기화 행을 전환하려면. 2.

수정 된 코드의 #pragma OMP를 추가하려면 문제가 해결

#pragma omp parallel private(x, y, seed) 
{ 
seed = 25234 + 17 * omp_get_thread_num(); 

#pragma omp for reduction(+:n) 
for (int i = 0; i < N; i++) { 

    x = (double) rand_r(&seed)/(double) RAND_MAX; 
    y = (double) rand_r(&seed)/(double) RAND_MAX; 

    if (x*x + y*y <= 1) 
     n++; 
} 

} 

을 읽습니다.

+0

대답은 무엇을 의미합니까? rand_r이 각 스레드에 대해 별도의 시퀀스를 지원할 것으로 기대하십니까? 확실히, 그러한 시퀀스 중 하나 이상은 같은 생성자의 단일 스레드 호출과 일치하지 않습니다. 두 개의 쓰레드가 동일한 순서로 떨어지면 true PRNG가 "잘못된"것으로 간주되지만 비 병렬 생성기를 사용하여 단축키를 사용할 경우에는 그런 보증이 없습니다. – tim18

+0

@ tim18 "answer is wrong"Pi의 결과 값이 3.14가 아니지만 (rand()가있는 순차 프로그램을 사용할 때 3.14). 예, 스레드 수에 따라 시드를 사용하기 때문에 각 스레드마다 별도의 시퀀스가 ​​필요합니다. 아니면 무언가를 놓치고 있습니까? ... – newt

+0

네가 뭔가를 놓친다. 루프의 각 반복에서 씨앗을 초기화하지 말고 한 번만. 당신이 ATM을하는 방식으로, 당신은 계속해서 똑같은 "무작위"번호를 반복 생성 할 것입니다. – Gilles

답변

0

분명히 rand_r()에는 rand()와 비교하여 더 많은 명령어가 있습니다. 아래는 한 구현에서 복사 한 것입니다. 따라서 rand_r()이 rand()보다 한 라운드 완료하는 데 더 많은 시간이 걸리는 것은 합리적입니다.

int 
rand_r(unsigned int *ctx) 
{ 
    u_long val = (u_long) *ctx; 
    int r = do_rand(&val); 

    *ctx = (unsigned int) val; 
    return (r); 
} 


static u_long next = 1; 

int 
rand() 
{ 
    return (do_rand(&next)); 
} 

그리고 rand()는 스레드로부터 안전하지 않으므로 rand()를 병렬로 사용하면 출력이 올바르지 않을 수 있습니다. 더 나쁜 부분은 여전히 ​​결과를 얻고 소규모 테스트에서 올바른지 여부를 모르는 것입니다.

+0

오케이.아마도 병렬 난수 생성을 위해 일부 라이브러리를 사용하여 병렬 방식으로 난수 생성을 할 때 어떤 이점을 얻을 수 있습니까? 그렇습니다. 필자는 내 것과 동일한 질문을 검토했으며 rand_r을 사용하여 성능을 향상시키는 것이 좋습니다. 그리고 pi 평가의 시간은 실제로 순차적 프로그램에 비해 감소했습니다. 그래서 내 경우에는 시간이 더 많이 걸린다는 것이 이상하다는 것입니다. 그리고 왜 여전히 병렬로 rand_r()가 결과가 잘못되었는지 (pi는 3.14와 같지 않음) 이해가되지 않지만 rand()를 순차적으로 사용하는 동안 올바른 것입니다. – newt