[英]What's a good way to seed a random number generator to work with forking?
Suppose I have a function generateId
to generate random 64-bit integers. 假设我有一个函数
generateId
来生成随机的64位整数。 If I write generateId
like this 如果我像这样写
generateId
uint64_t generateId() {
static thread_local std::mt19937_64 rng{std::random_device{}()};
return rng();
}
Then rng
won't get reseeded after a fork. 然后在叉子之后
rng
不会被重新接种。 Running 运行
int main() {
std::cout << generateId() << "\n";
if (fork() == 0) {
std::cout << "child: " << generateId() << "\n";
} else {
std::cout << "parent: " << generateId() << "\n";
}
return 0;
}
Will print the same number for child and parent. 将为孩子和父母打印相同的号码。
Is there a way I can write generateId
so that it reseeds for new processes but still remains performant. 有没有办法我可以编写
generateId
以便它为新进程重新种植,但仍然保持高性能。
Here's what I came up with: 这是我想出的:
class TlsRandomNumberGenerator {
public:
TlsRandomNumberGenerator() {
pthread_atfork(nullptr, nullptr, OnFork);
}
static uint64_t GenerateId() {
return random_number_generator_();
}
private:
static thread_local std::mt19937_64 random_number_generator_;
static void OnFork() {
random_number_generator_.seed(std::random_device{}());
}
};
thread_local std::mt19937_64 TlsRandomNumberGenerator::random_number_generator_{
std::random_device{}()};
uint64_t generateId() {
static TlsRandomNumberGenerator rng;
return TlsRandomNumberGenerator::GenerateId();
}
It will work with forking but also doesn't have the overhead of calling getpid
for every number generation, which depending on the version of libc you're using may or may not be cached so can involve a performance penalty. 它将与分叉一起使用,但也没有为每个数字生成调用
getpid
的开销,这取决于您正在使用的libc的版本可能会或可能不会被缓存,因此可能涉及性能损失。 See notes on getpid
: 请参阅
getpid
注释:
From glibc version 2.3.4 up to and including version 2.24, the glibc wrapper function for getpid() cached PIDs, with the goal of avoiding additional system calls when a process calls getpid() repeatedly.
从glibc版本2.3.4到版本2.24,glibc包装函数用于getpid()缓存的PID,目的是在进程重复调用getpid()时避免额外的系统调用。
This should work: 这应该工作:
uint64_t generateId() {
static pid_t mypid = 0;
static std::unqiue_ptr<std::mt19937_64> rng;
if( mypid != getpid() ) {
rng.reset();
mypid = getpid();
}
if( !rng )
rng = std::make_unique<std::mt19937_64>(std::random_device{}());
return (*rng)();
}
Note: this code is not thread safe, and I removed thread_local
assuming you tried to solve fork()
issue using it. 注意:此代码不是线程安全的,我删除了
thread_local
假设您尝试使用它解决fork()
问题。 If multithreading involved then proper locking is ncesessary as well as considerations on problems using mutexes
or non-blocking primitives with fork()
如果涉及多线程,那么正确的锁定是必要的,以及使用
fork()
使用mutexes
或非阻塞原语的问题的考虑
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.