2011-11-08 3 views
0

아래 코드는 어떤 이유로 든 모든 프로세스에 대해 동일한 난수를 반환하는 난수 생성기를 생성합니다. 어떻게 그럴 수 있니? 뮤텍스에 문제가 있습니까?PRNG가 모든 프로세스에서 동일한 값을 반환합니다.

#include <sys/types.h> 
#include <sys/wait.h> 
#include <pthread.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <time.h> 

#define RETURN_FAILURE_IF_TRUE(condition, ...) \ 
{ \ 
    if(condition) \ 
    { \ 
     fprintf(stderr, __VA_ARGS__); \ 
     return EXIT_FAILURE; \ 
    } \ 
} 

#define RETURN_FAILURE_IF_FALSE(condition, ...) \ 
    RETURN_FAILURE_IF_TRUE(!(condition), __VA_ARGS__) 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 

int nextRandomDouble(double* d) 
{ 
    if(pthread_mutex_lock(&mutex) != 0) return 0; 
    *d = drand48(); 
    if(pthread_mutex_unlock(&mutex) != 0) return 0; 
    return 1; 
} 

int main() 
{ 
    const int processes = 5; 
    srand48(time(NULL)); 

    for(int i = 0; i < processes; ++i) 
    { 
     pid_t pid = fork(); 
     RETURN_FAILURE_IF_TRUE(pid < 0, "Fork failed.\n"); 
     if(pid == 0) 
     { 
      double d; 
      RETURN_FAILURE_IF_FALSE(nextRandomDouble(&d), "PRNG failed.\n"); 
      printf("rnd: %f\n", d); 
      return EXIT_SUCCESS; 
     } 
    } 

    for(int i = 0; i < processes; ++i) 
    { 
     int status; 
     pid_t pid = waitpid(-1, &status, 0); 
     RETURN_FAILURE_IF_TRUE(
      (pid != 1) && (status != 0), "Child exit failed.\n" 
     ); 
    } 
    return EXIT_SUCCESS; 
} 

답변

1

fork()을 호출하기 전에 PRNG를 시드하기 때문에 각 프로세스에서 동일한 난수 시퀀스가 ​​생성됩니다. fork()에 대한 호출 후에 각 프로세스는 을가집니다. 동일한 값으로 시드 된 PRNG의 복사본입니다. 물론 각 프로세스는 동일한 일련의 번호를 가져옵니다.

fork() 이후 각 프로세스가 자체 가상 주소 공간에서 작동 중이므로 여기에 프로세스간에 공유 상태가 없으므로 뮤텍스 호출이 필요하지 않습니다. 별도의 스레드을 만드는

대신 fork()pthread_create()를 사용하는 경우, 다음 스레드는 PRNG의 상태를 공유하고 그들은 각각 PRNG 순서에서 다른 값을 얻을 것이다 :

void *thread_func(void *arg) 
{ 
    double d; 
    if (!nextRandomDouble(&d)) 
     fprintf(stderr, "PRNG failed.\n"); 
    else 
     printf("rnd: %f\n", d); 
    return 0; 
} 

int main() 
{ 
    const int processes = 5; 
    pthread_t thread[processes]; 
    srand48(time(NULL)); 

    for(int i = 0; i < processes; ++i) 
    { 
     int pthread_err = pthread_create(&thread[i], NULL, thread_func, NULL); 
     RETURN_FAILURE_IF_TRUE(pthread_err != 0, "pthread_create failed.\n"); 
    } 

    for(int i = 0; i < processes; ++i) 
    { 
     void *status; 
     int pthread_err = pthread_join(thread[i], &status); 
     if ((pthread_err != 0) || (status != 0)) 
      fprintf(stderr, "Child exit failed.\n"); 
    } 
    return EXIT_SUCCESS; 
} 
+0

좋은 대답은 실제로 주요 문제인 것으로 보이는 것을 강조합니다. 질문자는 프로세스를 스레드와 혼동하고 있습니다. – Quantumboredom

3
srand48(time(NULL)); 

당신은 두 번째로, 프로세스가 시작된 시간에 각 프로세스의 PRNG 씨앗. 즉, 동일한 두 번째로 시작하는 모든 프로세스가 동일한 값을 갖는 PRNG를 시드합니다.

시도 :

srand48((getpid()*2654435761U)^time(NULL)); 
+0

는 당신이 우리를 계몽 할 수 있습니다 이 마법의 숫자는 무엇을위한 것인가? –

+0

그것은 [Knuth] (http://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key/665545#665545)에서 유래합니다. 이는 PID의 비트를 혼합하는 간단한 방법이므로 결국 몇 비트 만 다른 PID는 몇 초 만에 차이가 나는 시간을 상쇄하지 않습니다. 9802-> F819732A 9803-> 9650ECDB 9804-> 3488668C 9805-> D2BFE03D. 얼마나 많은 비트가 다른지 확인하십시오. –

+0

영리합니다. 그 상수에 대한 빠른 구글은 그동안 생산적이었습니다. 참고로 이것은 계몽입니다 : http://mathforum.org/kb/thread.jspa?messageID=431065&tstart=0 –

0

drand48을 사용하여 멀티 스레드 환경에서 나쁜 생각이다. 이것은 통화 사이에 공유 글로발 상태를 사용하고 있습니다. 따라서 스레드가 서로의 발걸음을 옮기거나 (스레드가 안전하지 않은 경우) 스레드가 차례대로 끝없이 기다립니다 (액세스가 뮤텍스 인 경우).

대신 erand48을 사용하십시오. 이것은 각 스레드에 대해 다른 값으로 초기화해야하는 인수의 상태를 수신합니다.

관련 문제