2011-10-17 23 views
7

私はいくつかのスレッドが並行して動作しており、それぞれが乱数を生成しなければなりません。私は、メインスレッドでsrandを使ってランダムジェネレータを初期化するのが正しいかどうか、またはすべてのスレッドが独自のランダムジェネレータを初期化する必要があるかどうかを理解するパターンがあるかどうかを理解したい。 rand/srandはスレッドで使用するようには設計されていないようで、スレッドと乱数をどうやって処理できるのだろうかと思っています。 ありがとうpthreadを使ってCで乱数を生成する最も正しい方法は何ですか

編集:私は純粋な乱数が必要ですが、私はテスト目的のために決定論的なシーケンスを生成することにも興味があります。私はLinuxを使っていますが、できるだけポータブルなコードを書いています。

+2

シーケンスを確定的にしたいのですか? - http://stackoverflow.com/questions/6467585/deterministic-random-number-generator-tied-to-instance-thread-independent/6467623#6467623 – Flexo

+1

特別な要件がない場合は、 'rand_r'を使用してください。 –

+1

rand()はlinuxではスレッドセーフですが、posixはそのためにrand_rを提供していますが、posixではそうである必要はありません。 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システムで

(あなたがあるように見えるところ)erand48nrand48jrand48は、入力値として乱数生成器の状態を取る機能の*rand48家族があります。したがって、各スレッドに独立した状態を簡単に持たせることができます。既知の番号(例:スレッドの番号)で初期化でき、乱数の再現性のあるシーケンスが得られます。または、現在の時刻&のような、予測不可能なもので初期化すると、実行ごとに異なるシーケンスを持つことになります。

1

rand_rはスレッドセーフですが、リエントラントです。

以下のコードは、xorshiftアルゴリズムを使用してuint128_t擬似乱数を生成します。

追加のプロパティ:

  • 共有リエントラント
  • ロックフリー
  • スレッドセーフ
  • 超高速enthropy

uintx_typesの2つの変種源から播種

  • 。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の:

    #define KEYS 1000 
    
    int main(int argc, char **argv) 
    { 
        int    i; 
        uint128_t  key; 
    
        srand_init(); 
    
        for(i = 0; i <= KEYS; i++) 
        { 
         key = rand_range_128(UINT128_MIN, UINT128_MAX); 
         printf("%016"PRIx64"%016"PRIx64"\n", (uint64_t)(key >> 64), (uint64_t)key); 
    
        } 
        return 0; 
    } 
    

    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); 
    } 
    

    :ようにあなたは、関数を使用することができますLinuxシステムでは

  • +0

    srand_init(unsigned int * seed)内のsrand_init(void)を変更して、 の代わりにclock_gettime(CLOCK_REALTIME、&ts); r [0] =(uint64_t)(ts))の代わりに "necroposting" .tv_sec * 1.0e9 + ts.tv_nsec); 単純にr [0] = uint64_t(* seed)を置くので、いつでもrngを初期化する方法を選択できます。 –

    +0

    さらに、このスレッドをスレッドセーフな方法で初期化する必要がありますか?スレッドを生成してシードを変更し、スレッドごとにsrand_init(seed)を使用するか、パラレル化された領域内でran​​d_range_128(UINT128_MIN、UINT128_MAX)を安全に呼び出すことができますか? –

    0

    (min、max)の有効なRNGですが、いくつかの乱数が必要な単純なベンチマークを書くためには少なくとも働きました。

    このように、関数はPOSIXスレッドIDを使用してランダムシードを再配置します。そうすることで、各スレッドは、グローバル状態を使用する代わりに、独自のランダムシードを持ちます。time(NULL)

    関連する問題