I have several threads running concurrently and each of them must generate random numbers. I want to understand if there is a pattern to follow, to understand if it is correct to initialize the random generator with srand in the main thread or if every thread must initialize its own random generator. It seems that rand/srand have not been designed to be used with threads and I'm wondering how I can deal with threads and random numbers together. Thanks
我有几个并发运行的线程,每个线程都必须生成随机数。我想了解是否存在要遵循的模式,以了解在主线程中使用srand初始化随机生成器是否正确,或者每个线程是否必须初始化其自己的随机生成器。似乎rand / srand没有被设计为与线程一起使用,我想知道如何处理线程和随机数。谢谢
EDIT: I need pure random numbers, but I'm also interested in generating a deterministic sequence for testing purposes. I'm on linux, but I prefer to write code as portable as possible.
编辑:我需要纯随机数,但我也有兴趣为测试目的生成确定性序列。我在Linux上,但我更喜欢尽可能地编写代码。
6 个解决方案
#1
8
On Linux you can use the rand_r() for a mediocre generator or the drand48_r() function for a much better one. Both are thread safe replacements for rand()
and drand48()
, by taking a single argument consisting of the current state, instead of using global state.
在Linux上,您可以将rand_r()用于普通生成器或drand48_r()函数以获得更好的生成器。两者都是rand()和drand48()的线程安全替换,通过采用由当前状态组成的单个参数,而不是使用全局状态。
With regard to your question on initialization, both of the generators above allow you to seed at whatever point you desire, so you are not forced to seed them before spawning your threads.
关于初始化的问题,上面的两个生成器都允许你在你想要的任何点播种,所以在产生你的线程之前你不会*播种它们。
#2
4
When working with threads and doing e.g simulations or so it is very important that you have the random generators independent. First, dependencies between them can really bias your results and then mechanisms for access control to the state of the random generator will most likely slow down execution.
当使用线程并进行例如模拟时,将随机生成器独立起来非常重要。首先,它们之间的依赖关系可能会对结果产生偏差,然后对随机生成器状态的访问控制机制很可能会降低执行速度。
On POSIX systems (where you seem to be) there is the *rand48
family of functions where erand48
, nrand48
and jrand48
take the state of the random generator as input values. So you can easily have independent states in each thread. Those you can initialize with a known number (e.g the number of your thread) and you'd have a reproducible sequence of random numbers. Or you initialize it with something non-predicable such as the current time & the number to have sequences that vary for each execution.
在POSIX系统(你似乎是)上有* rand48系列函数,其中erand48,nrand48和jrand48将随机生成器的状态作为输入值。因此,您可以在每个线程中轻松拥有独立状态。那些你可以使用已知数字(例如你的线程数)进行初始化,并且你有一个可重现的随机数序列。或者,您可以使用不可预测的内容对其进行初始化,例如当前时间和数字,以使序列在每次执行时都有所不同。
#3
1
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 this is tagged C, not C++).
在Windows上,您可以使用rand_s()函数,该函数是线程安全的。如果你已经在使用Boost,那么boost :: random是胜任的(虽然我很欣赏这是标记C,而不是C ++)。
#4
1
rand_r is thread-safe but also is reentrant.
rand_r是线程安全的,但也是可重入的。
Code below generates uint128_t pseuso-random numbers using xorshift algorithm.
下面的代码使用xorshift算法生成uint128_t pseuso-random数字。
Additional properties:
- shared-reentrant
- lock-free
- thread-safe
- ultrafast
- seeded from two variant sources of enthropy
来自两个变异的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:
#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.
在Linux下用gcc(4.9.2)编译。
#5
0
This link provides some code for reading from /dev/random -- which should be thread-safe -- and the question is along the same lines:
这个链接提供了一些从/ dev / random读取的代码 - 这应该是线程安全的 - 问题是同样的:
Is reading /dev/urandom thread-safe?
读/ dev / urandom线程安全吗?
#6
0
On Linux systems you can use a function like:
在Linux系统上,您可以使用以下功能:
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 don´t really know if numbers generated by this function fit to normal distribution in other words if this function is a valid RNG in the range (min,max) but at least worked for me to write a simple benchmark that required some random numbers.
在这里我不得不说,我不知道这个函数生成的数字是否适合正态分布,换句话说,如果这个函数是范围内的有效RNG(min,max),但至少对我来说写一个简单的需要一些随机数的基准。
As you can see, the function utilizes the POSIX thread id in order to re-arrange the random seed. Doing so, each thread has it own random seed instead of using global state depending on time(NULL)
如您所见,该函数利用POSIX线程ID来重新排列随机种子。这样做,每个线程都有自己的随机种子,而不是使用全局状态,具体取决于时间(NULL)
#1
8
On Linux you can use the rand_r() for a mediocre generator or the drand48_r() function for a much better one. Both are thread safe replacements for rand()
and drand48()
, by taking a single argument consisting of the current state, instead of using global state.
在Linux上,您可以将rand_r()用于普通生成器或drand48_r()函数以获得更好的生成器。两者都是rand()和drand48()的线程安全替换,通过采用由当前状态组成的单个参数,而不是使用全局状态。
With regard to your question on initialization, both of the generators above allow you to seed at whatever point you desire, so you are not forced to seed them before spawning your threads.
关于初始化的问题,上面的两个生成器都允许你在你想要的任何点播种,所以在产生你的线程之前你不会*播种它们。
#2
4
When working with threads and doing e.g simulations or so it is very important that you have the random generators independent. First, dependencies between them can really bias your results and then mechanisms for access control to the state of the random generator will most likely slow down execution.
当使用线程并进行例如模拟时,将随机生成器独立起来非常重要。首先,它们之间的依赖关系可能会对结果产生偏差,然后对随机生成器状态的访问控制机制很可能会降低执行速度。
On POSIX systems (where you seem to be) there is the *rand48
family of functions where erand48
, nrand48
and jrand48
take the state of the random generator as input values. So you can easily have independent states in each thread. Those you can initialize with a known number (e.g the number of your thread) and you'd have a reproducible sequence of random numbers. Or you initialize it with something non-predicable such as the current time & the number to have sequences that vary for each execution.
在POSIX系统(你似乎是)上有* rand48系列函数,其中erand48,nrand48和jrand48将随机生成器的状态作为输入值。因此,您可以在每个线程中轻松拥有独立状态。那些你可以使用已知数字(例如你的线程数)进行初始化,并且你有一个可重现的随机数序列。或者,您可以使用不可预测的内容对其进行初始化,例如当前时间和数字,以使序列在每次执行时都有所不同。
#3
1
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 this is tagged C, not C++).
在Windows上,您可以使用rand_s()函数,该函数是线程安全的。如果你已经在使用Boost,那么boost :: random是胜任的(虽然我很欣赏这是标记C,而不是C ++)。
#4
1
rand_r is thread-safe but also is reentrant.
rand_r是线程安全的,但也是可重入的。
Code below generates uint128_t pseuso-random numbers using xorshift algorithm.
下面的代码使用xorshift算法生成uint128_t pseuso-random数字。
Additional properties:
- shared-reentrant
- lock-free
- thread-safe
- ultrafast
- seeded from two variant sources of enthropy
来自两个变异的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:
#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.
在Linux下用gcc(4.9.2)编译。
#5
0
This link provides some code for reading from /dev/random -- which should be thread-safe -- and the question is along the same lines:
这个链接提供了一些从/ dev / random读取的代码 - 这应该是线程安全的 - 问题是同样的:
Is reading /dev/urandom thread-safe?
读/ dev / urandom线程安全吗?
#6
0
On Linux systems you can use a function like:
在Linux系统上,您可以使用以下功能:
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 don´t really know if numbers generated by this function fit to normal distribution in other words if this function is a valid RNG in the range (min,max) but at least worked for me to write a simple benchmark that required some random numbers.
在这里我不得不说,我不知道这个函数生成的数字是否适合正态分布,换句话说,如果这个函数是范围内的有效RNG(min,max),但至少对我来说写一个简单的需要一些随机数的基准。
As you can see, the function utilizes the POSIX thread id in order to re-arrange the random seed. Doing so, each thread has it own random seed instead of using global state depending on time(NULL)
如您所见,该函数利用POSIX线程ID来重新排列随机种子。这样做,每个线程都有自己的随机种子,而不是使用全局状态,具体取决于时间(NULL)