2011-10-17 4 views
7

여러 스레드가 동시에 실행되고 각각이 난수를 생성해야합니다. 내가 따라야 할 패턴이 있는지, 주 스레드에서 srand를 사용하여 임의 생성기를 초기화하는 것이 올바른지 또는 모든 스레드가 자체 임의 생성기를 초기화해야 하는지를 이해하고 싶습니다. 그것은 rand/srand 스레드와 함께 사용하도록 설계되지 않은 것 및 스레드 및 임의의 숫자 함께 함께 처리 할 수 ​​있습니다 궁금하네요. 감사합니다.pthread를 사용하여 C에서 난수를 생성하는 가장 올바른 방법은 무엇입니까

편집 : 순수한 난수가 필요하지만, 테스트 목적으로 결정 성있는 시퀀스를 생성하는 데에도 관심이 있습니다. 나는 리눅스에 있지만, 나는 가능한 한 이식성있는 코드를 작성하는 것을 선호한다.

+2

시퀀스가 ​​결정적 이길 원합니까? - http://stackoverflow.com/questions/6467585/deterministic-random-number-generator-tied-to-instance-thread-independent/6467623#6467623 – Flexo

+1

특별한 요구 사항이 없다면'rand_r'을 사용하십시오. –

+1

rand()는 리눅스에서는 thread safe하지만, posix는 그 목적을 위해 rand_r을 제공하지만 반드시 그렇게 할 필요는 없다. glibc는 rand()에 내부 뮤텍스를 사용합니다. 스레드가 많은 난수를 생성 할 경우 경합을 일으킬 수 있습니다. – nos

답변

7

Linux의 경우 평범한 생성기에는 rand_r()을 사용하거나 훨씬 더 좋은 생성자는 drand48_r() 함수를 사용할 수 있습니다. 둘 다 rand()drand48()에 대한 스레드 안전 대체이며 전역 상태를 사용하는 대신 현재 상태로 구성된 단일 인수를 사용합니다.

초기화에 관한 질문에 관해서는 위의 두 생성기를 통해 원하는 모든 지점에 시드 할 수 있으므로 스레드를 생성하기 전에 시드해야합니다.

+1

POSIX 2008 이후 rand_r은 더 이상 사용되지 않습니다. 이유는 모르지만 좋아할 것입니다. –

0

Windows에서는 스레드 안전 인 rand_s() 함수를 사용할 수 있습니다. Boost를 이미 사용하고 있다면 boost::random이 유능합니다 (C++이 아니라 C라는 태그가 붙어있어서 고맙겠습니다). 스레드 안전해야하는 - -

4

스레드와 협력하고 예를 들어 시뮬레이션이나 무작위 생성기를 독립적으로 사용하는 것이 매우 중요합니다. 첫째, 이들 사이의 의존 관계로 인해 결과가 실제로 편향 될 수 있으며, 랜덤 생성기의 상태에 대한 액세스 제어 메커니즘이 실행 속도를 늦추 게됩니다.

POSIX 시스템에서 (있는 것처럼 보입니다) erand48, nrand48jrand48이 입력 값으로 사용되는 *rand48 패밀리가 있습니다. 따라서 각 스레드마다 독립적 인 상태를 쉽게 가질 수 있습니다. 알려진 숫자 (예 : 스레드 수)로 초기화 할 수 있으며 재현 가능한 일련의 난수가 있습니다. 또는 현재 시간 &과 같이 예측할 수없는 값으로 초기화하면 각 실행마다 순서가 달라집니다.

1

rand_r은 스레드로부터 안전하지만 재 입력 가능합니다.

아래 코드는 xorshift 알고리즘을 사용하여 uint128_t pseuso 난수를 생성합니다.

추가 속성 :

  • 공유 재진입
  • 잠금이없는
  • 스레드 안전
  • 초고속 enthropy

uintx_types의 두 변종 소스에서 시드

  • .H :

    #ifndef UINTX_TYPES_H_INCLUDED 
    #define UINTX_TYPES_H_INCLUDED 
    
    #include <inttypes.h> 
    #include <ctype.h> 
    
    typedef __uint128_t  uint128_t; 
    typedef __uint64_t  uint64_t; 
    
    #define UINT128_C(hi, lo) (((uint128_t)(hi) << 64) | (uint128_t)(lo)) 
    #define UINT128_MIN   UINT128_C(0x0000000000000000, 0x0000000000000000) 
    #define UINT128_0   UINT128_MIN 
    #define UINT128_MAX   (~(UINT128_0) - 1) 
    
    #endif // UINTX_TYPES_H_INCLUDED 
    

    lf.h :

    #ifndef LF_H_INCLUDED 
    #define LF_H_INCLUDED 
    
    #define AAF(ADDR, VAL)   __sync_add_and_fetch((ADDR), (VAL)) 
    
    #endif // LF_H_INCLUDED 
    

    rand.h :

    #ifndef RAND_H_INCLUDED 
    #define RAND_H_INCLUDED 
    
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <stdint.h> 
    #include <time.h> 
    #include <limits.h> 
    #include <fcntl.h> 
    #include <sys/types.h> 
    #include <unistd.h> 
    
    #include "lf.h" 
    #include "uintx_types.h" 
    
    
    #define URANDOM  "/dev/random" 
    
    void  srand_init(void); 
    uint128_t rand_range_128(uint128_t min, uint128_t max); 
    
    #endif // RAND_H_INCLUDED 
    

    rand.c :

    #include "rand.h" 
    
    uint64_t r[2]; 
    
    uint64_t xorshift64star(int index) 
    { 
        uint64_t x; 
    
        x = r[index]; 
        x ^= x >> 12; // a 
        x ^= x << 25; // b 
        x ^= x >> 27; // c 
        x = x * UINT64_C(2685821657736338717); 
        return AAF(&r[index], x); 
    } 
    
    void srand_init(void) 
    { 
        struct timespec ts; 
        size_t   nbytes; 
        ssize_t   bytes_read; 
        int    fd; 
    
        clock_gettime(CLOCK_REALTIME, &ts); 
        r[0] = (uint64_t)(ts.tv_sec * 1.0e9 + ts.tv_nsec); 
        xorshift64star(0); 
    
        if ((fd = open(URANDOM, O_RDONLY, S_IRUSR | S_IRGRP | S_IROTH)) == -1) 
        { 
         r[1] = r[0] + 1; 
         xorshift64star(1); 
        } 
        else 
        { 
         nbytes = sizeof(r[1]); 
         bytes_read = read(fd, &r[1], nbytes); 
         if ((bytes_read == 0) || (r[1] == 0ull)) 
         { 
          r[1] = r[0] + 1; 
          xorshift64star(1); 
         } 
         close(fd); 
        } 
    } 
    
    uint64_t rand_64(void) 
    { 
        return xorshift64star(0); 
    } 
    
    uint128_t rand_128(void) 
    { 
        uint128_t  r; 
    
        r = xorshift64star(0); 
        r = (r << 64) | xorshift64star(1); 
        return r; 
    } 
    
    
    uint128_t rand_range_128(uint128_t min, uint128_t max) 
    { 
        return (rand_128() % (max+1-min))+min; 
    } 
    

    TEST.C :

    0,123,172,057,313,

    Linux에서 gcc (4.9.2)로 컴파일하십시오. 내가 즉 정규 분포에이 기능을 맞춤에 의해 생성 된 번호는이 기능이있는 경우 만약 내가 정말하지는 알고 말을 여기

    size_t random_between_range(size_t min, size_t max){ 
        unsigned short state[3]; 
        unsigned int seed = time(NULL) + (unsigned int) pthread_self(); 
        memcpy(state, &seed, sizeof(seed)); 
        return min + nrand48(state) % (max - min); 
    } 
    

    :처럼이 기능을 사용할 수 있습니다 리눅스 시스템에서

  • +0

    여기에 "necroposting"으로 미안하지만 srand_init (unsigned int * seed)에서 srand_init (void)를 수정할 수 있는지 물어보고 싶었고 대신 clock_gettime (CLOCK_REALTIME, &ts); r [0] = (uint64_t) .tv_sec * 1.0e9 + ts.tv_nsec); 단순히 r [0] = uint64_t (* seed)를 넣으므로 항상 내 rng를 초기화하는 방법을 선택할 수 있습니다 .. –

    +0

    또한 스레드 세이프 방식으로이 rng를 어떻게 초기화해야합니까? 스레드를 생성 한 다음 시드를 변경하고 모든 스레드에서 srand_init (seed)를 사용합니까? 아니면 안전하게 병렬 처리 된 영역에서 rand_range_128 (UINT128_MIN, UINT128_MAX)을 호출 할 수 있습니까? –

    0

    유효한 RNG를 범위 (최소, 최대)로 설정했지만 적어도 임의의 숫자가 필요한 간단한 벤치 마크를 작성하는 데는 효과적이었습니다.

    이 함수는 임의의 시드를 재정렬하기 위해 POSIX 스레드 ID를 사용합니다. 그렇게하면, 각 쓰레드는 전역 상태를 사용하는 대신 자신의 임의의 시드를 갖습니다. time(NULL)

    관련 문제