How do I use rand_r and how do I use it in a thread safe way?(如何使用 rand_r 以及如何以线程安全的方式使用它?)
问题描述
我正在尝试学习如何使用 rand_r,并在阅读了这个问题后 我仍然有点困惑,有人可以看看并指出我遗漏了什么吗?据我了解, rand_r 使用一个指向某个值(或一块具有某个初始值的内存)的指针,并在每次调用时使用它来生成新数字.每个调用 rand_r 的线程都应该为它提供一个唯一的指针(或一块内存),以获得不同线程之间的实际随机"数字.这就是为什么:
I am trying to learn how to use rand_r, and after reading this question I am still a little confused, can someone please take a look and point out what I'm missing? To my understanding, rand_r takes a pointer to some value (or a piece of memory with some initial value) and use it to generate new numbers every time it is called. Each thread that calls rand_r should supply it with a unique pointer (or piece of memory) to get "actual random" numbers between different threads. That's why this:
int globalSeed;
//thread 1
rand_r(&globalSeed);
//thread 2
rand_r(&globalSeed);
是错误的使用方式.如果我有
is the wrong way of using it. If I have
int seed1,seed2;
//thread 1
rand_r(&seed1);
//thread 2
rand_r(&seed2);
这将是在线程之间生成真正随机"数字的正确方法?
this would be the right way to generate "true random" numbers between threads?
阅读以上部分的答案后的其他问题:
additional questions after reading answers to the above part:
- 如果在线程 1 我需要一个随机1到n之间的数字,我应该做
(rand_r(&seed1) % (n-1)) + 1
?或者还有其他常见的方法吗? - 如果种子的内存是动态分配的,这是正确的还是正常的?
- if in thread 1 I need a random
number between 1 to n, should I do
(rand_r(&seed1) % (n-1)) + 1
? Or there is other common way of doing this? - Is it right or normal if the memory for the seed is dynamically allocated?
推荐答案
没错.您在第一种情况下所做的是绕过 rand_r
的线程安全特性.对于许多非线程安全函数,持久状态存储在对该函数的调用之间(例如此处的随机种子).
That's correct. What you're doing in the first case is bypassing the thread-safety nature of rand_r
. With many non-thread-safe functions, persistent state is stored between calls to that function (such as the random seed here).
使用线程安全变体,您实际上提供了一个特定于线程的数据(seed1
和 seed2
)以确保状态不会在线程之间共享.
With the thread-safe variant, you actually provide a thread-specific piece of data (seed1
and seed2
) to ensure the state is not shared between threads.
请记住,这不会使数字真正随机,只会使序列彼此独立.如果您使用相同的种子启动它们,您可能会在两个线程中获得相同的序列.
Keep in mind that this doesn't make the numbers truly random, it just makes the sequences independent of each other. If you start them with the same seed, you'll probably get the same sequence in both threads.
举个例子,假设你得到一个随机序列 2, 3, 5, 7, 11, 13, 17 给定初始种子 0.使用共享种子,交替调用 rand_r
来自两个不同的线程会导致这个:
By way of example, let's say you get a random sequence 2, 3, 5, 7, 11, 13, 17 given an initial seed of 0. With a shared seed, alternating calls to rand_r
from two different threads would cause this:
thread 1 thread 2
<--- 2
3 --->
<--- 5
7 --->
<--- 11
13 --->
<--- 17
这是最好的情况 - 您实际上可能会发现共享状态已损坏,因为它的更新可能不是原子的.
and that's the best case - you may actually find that the shared state gets corrupted since the updates on it may not be atomic.
具有非共享状态(a
和 b
代表随机数的两个不同来源):
With non-shared state (with a
and b
representing the two different sources of the random numbers):
thread 1 thread 2
<--- 2a
2b --->
<--- 3a
3b --->
<--- 5a
5b --->
::
一些线程安全调用要求您提供这样的线程特定状态,其他人可以在幕后创建线程特定数据(使用线程 ID 或类似信息),这样您就无需担心,并且您可以在线程和非线程环境中使用完全相同的源代码.我自己更喜欢后者,因为它让我的生活更轻松.
Some thread-safe calls require you to provide the thread-specific state like this, others can create thread-specific data under the covers (using a thread ID or similar information) so that you never need to worry about it, and you can use exactly the same source code in threaded and non-threaded environments. I prefer the latter myself, simply because it makes my life easier.
编辑问题的其他内容:
<代码>>如果在线程 1 中,我需要一个 1 到 n 之间的随机数,我应该执行 '(rand_r(&seed1) % (n-1)) + 1',还是有其他常用的方法?
假设您想要一个介于 1
和 n
inclusive 之间的值,请使用 (rand_r(&seed1) % n) +1
.第一位为您提供一个从 0
到 n-1
(含)的值,然后加 1 以获得所需的范围.
Assuming you want a value between 1
and n
inclusive, use (rand_r(&seed1) % n) + 1
. The first bit gives you a value from 0
to n-1
inclusive, then you add 1 to get the desired range.
<代码>>动态分配给种子的内存是对的还是正常的?
只要您在使用种子,它就必须具有持久性.您可以在线程中动态分配它,但也可以在线程的顶级函数中声明它.在这两种情况下,您都需要以某种方式将地址传达给较低级别(除非您的线程只是一个不太可能的函数).
The seed has to be persistent as long as you're using it. You could dynamically allocate it in the thread but you could also declare it in the thread's top-level function. In both those cases, you'll need to communicate the address down to the lower levels somehow (unless your thread is just that one function which is unlikely).
您可以通过函数调用将其传递下去,也可以以某种方式设置一个全局数组,以便下层可以发现正确的种子地址.
You could either pass it down through the function calls or set up a global array somehow where the lower levels can discover the correct seed address.
或者,因为无论如何您都需要一个全局数组,所以您可以拥有一个全局种子数组而不是种子地址,低层可以使用它来发现他们的种子.
Alternatively, since you need a global array anyway, you can have a global array of seeds rather than seed addresses, which the lower levels could use to discover their seed.
您可能(在使用全局数组的两种情况下)都有一个键控结构,其中包含线程 ID 作为键和要使用的种子.然后,您将不得不编写您的自己的 rand()
例程,该例程可以找到正确的种子并使用它调用 rand_r()
.
You would probably (in both cases of using the global array) have a keyed structure containing the thread ID as a key and the seed to use. You would then have to write your own rand()
routine which located the correct seed and called rand_r()
with that.
这就是为什么我更喜欢使用线程特定数据在幕后执行此操作的库例程.
This is why I prefer library routines which do this under the covers with thread-specific data.
这篇关于如何使用 rand_r 以及如何以线程安全的方式使用它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何使用 rand_r 以及如何以线程安全的方式使用它?
- Stroustrup 的 Simple_window.h 2022-01-01
- 与 int by int 相比,为什么执行 float by float 矩阵乘法更快? 2021-01-01
- 使用/clr 时出现 LNK2022 错误 2022-01-01
- 近似搜索的工作原理 2021-01-01
- C++ 协变模板 2021-01-01
- 从python回调到c++的选项 2022-11-16
- 静态初始化顺序失败 2022-01-01
- 如何对自定义类的向量使用std::find()? 2022-11-07
- 一起使用 MPI 和 OpenCV 时出现分段错误 2022-01-01
- STL 中有 dereference_iterator 吗? 2022-01-01