What is the most correct way to generate random numbers in C with pthread

I have several threads working at the same time, and each of them should generate random numbers. I want to understand whether to follow the pattern in order to understand whether it is correct to initialize a random generator with srand in the main thread or each thread must initialize its own random generator. It seems that rand / srand was not designed for use with streams, and I am wondering how I can handle streams and random numbers together. Thanks

EDIT: I need pure random numbers, but I'm also interested in creating a deterministic sequence for testing purposes. I am on Linux, but I prefer to write code as portable as possible.

+7
source share
6 answers

On Linux, you can use rand_r () for a mediocre generator or drand48_r () for much better. Both are thread-safe replacements for rand() and drand48() , taking a single argument consisting of the current state, instead of using the global state.

As for your initialization question, both of the above generators allow you to sow at any time you want, so you should not sow them before creating your own threads.

+7
source

When working with streams and, for example, in simulations or it is very important that you have independent random generators. First, dependencies between them can really bias your results, and then access control mechanisms to the state of a random generator will most likely slow down execution.

On POSIX systems (where you seem to be) there is a family of *rand48 functions, where erand48 , nrand48 and jrand48 take the state of a random generator as input values. This way you can easily have independent states in each thread. Those that you can initialize with a known number (for example, the number of your stream), and you will have a reproducible sequence of random numbers. Or you initialize it with something unpredictable, such as the current time and number, to have sequences that differ for each execution.

+4
source

rand_r is thread safe, but also reentrant.

Below is the uint128_t code of pseudo random numbers using the xorshift algorithm.

Additional properties:

  • shared return
  • non-blocking
  • thread safe
  • superfast
  • sown from two sources of entropy

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:

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

Compile with gcc (4.9.2) under Linux.

+1
source

On Windows, you can use the rand_s () function, which is thread safe. If you are already using Boost, then boost :: random is competent (although I appreciate that it is tagged C, not C ++).

0
source

This link contains some code to read from / dev / random - which should be thread safe - and the question goes along the same lines:

Is reading / dev / urandom thread safe?

0
source

On Linux systems, you can use a feature such as:

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

Here I have to say that I really do not know if the numbers generated by this function correspond to the normal distribution, in other words, if this function is a valid RNG in the range (min, max), but at least it worked for me, write a simple test, requiring some random numbers.

As you can see, the function uses the POSIX stream identifier to reorder the random seed. Moreover, each thread has its own random seed instead of the global state depending on time(NULL)

0
source

All Articles