rand_r is thread-safe but also is reentrant.
Code below generates uint128_t pseuso-random numbers using xorshift algorithm.
Additional properties:
- shared-reentrant
- lock-free
- thread-safe
- ultrafast
- seeded from two variant sources of 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.
rand_r
. – Inclination