在 C/C++ 中对多线程程序使用 rand_r 的正确方法
Correct way to use rand_r for multithreaded programs in C/C++
所以,我需要一些有关 C++ 中多线程的帮助。我想让我的多个线程使用一个低于 800 的随机数调用函数 usleep。但是,根据我的理解,rand_r 必须在每个线程中使用不同的整数作为种子。
My confusion 源于这样一个事实,即如果我想为每个线程的 rand_r 使用不同的整数,那么我该怎么做呢?如果我不能创建随机整数,我怎么能为每个线程使用不同的(即随机的)整数?
static unsigned int consumerseed = 1;
static unsigned int producerseed = 54321;
//producer thread:
void *producer(void *param) {
buffer_item rand;
while (1) {
//sleep for a random period of time:
int producersleeptime = rand_r(&producerseed)%500+100;
usleep(producersleeptime);
//produce an item:
//wait on both semaphores
//attempt to insert into buffer
//signal both semaphores
}
}
//consumer thread:
void *consumer(void *param) {
buffer_item rand;
while (1) {
//sleep for a random period of time:
int consumersleeptime = rand_r(&consumerseed)%600+200;
usleep(consumersleeptime);
//wait on both semaphores
//attempt to remove an item from buffer
//signal both semaphores
}
}
我在程序的顶部定义了静态整数生产者种子和消费者种子,作为全局变量。我这样做是因为我认为对 rand_r 的调用需要访问一个静态的、不变的内存位置。
这是执行此操作的正确方法吗?或者我需要每个线程 不同的 整数。这会导致我的线程中出现任何竞争条件吗?生成的随机数怎么样 -- 每次都会不同吗?
编辑 1: 好吧,这个问题的答案基本上是不正确。每个线程都需要一个 unique 种子整数。例如,这可以来自 time() 或 p_thread_self() id。我仍然对如何准确地实现这一点感到困惑,但我会继续努力并报告回来。现在我决定使用 p_thread_self 作为每个线程的种子。
非常感谢您抽出时间来 look/answer。
My confusion stems from the fact that if I want a different integer to
be used for rand_r for each thread, then how can I do this? How can I
have a different (ie. random) integer be used for each thread, if I
can't create random integers?
这里需要使用线程专用变量。所以你可以使用这些方法。
pthread_setspecific() & pthread_getspecific()
这用于创建全局变量,但仍特定于每个线程(不共享):它们是特定于线程的全局变量。
这个例子有很好的例子
- 每个线程需要 1 个种子,而不是全局种子。
- 要为每个线程生成唯一的种子,请从主线程调用
time()
以获取第一个种子。然后对于每个新线程,将一个添加到当前种子以获得下一个种子。例如,如果 time()
返回 100,则您的种子将为 100、101、102 等。您的主线程需要将种子作为参数的一部分传递给每个线程。
编辑:
- 如以下评论所示,您可以获取初始种子(上例中的
100
)并将其与线程 ID 混合(使用异或或加法)。这样你就不必将种子传递给每个线程。至于 only 使用线程 id 作为种子,那也可以。但是,在新的 运行 上,您可能会获得与之前的 运行 相同的线程 ID(取决于您的 OS 确定线程 ID 的方式)。因此,如果您不想依赖 OS 生成线程 ID 的方式,您仍应使用一些初始种子,例如时间。
在 C++11 中,您可以使用 std::random_device
在每个线程上简单地创建另一个独立的种子。这与您在单线程代码中所做的完全相同。然后您可以在 std::this_thread
.
上调用 thread::sleep()
#include <random>
#include <thread>
#include <chrono>
thread_local std::random_device rd; // used once only per thread to initialise RNG
thread_local std::mt19937 rng(rd()); // thread-specific RNG
std::uniform_int_distribution<int> uni(0,800); // guaranteed unbiased
// called possibly many times
std::this_thread::sleep_for(uni(rng)*std::chrono::microseconds);
特别是,没有必要(滥用)使用当前时间作为种子 and/or 其他相关种子。
所以,我需要一些有关 C++ 中多线程的帮助。我想让我的多个线程使用一个低于 800 的随机数调用函数 usleep。但是,根据我的理解,rand_r 必须在每个线程中使用不同的整数作为种子。
My confusion 源于这样一个事实,即如果我想为每个线程的 rand_r 使用不同的整数,那么我该怎么做呢?如果我不能创建随机整数,我怎么能为每个线程使用不同的(即随机的)整数?
static unsigned int consumerseed = 1;
static unsigned int producerseed = 54321;
//producer thread:
void *producer(void *param) {
buffer_item rand;
while (1) {
//sleep for a random period of time:
int producersleeptime = rand_r(&producerseed)%500+100;
usleep(producersleeptime);
//produce an item:
//wait on both semaphores
//attempt to insert into buffer
//signal both semaphores
}
}
//consumer thread:
void *consumer(void *param) {
buffer_item rand;
while (1) {
//sleep for a random period of time:
int consumersleeptime = rand_r(&consumerseed)%600+200;
usleep(consumersleeptime);
//wait on both semaphores
//attempt to remove an item from buffer
//signal both semaphores
}
}
我在程序的顶部定义了静态整数生产者种子和消费者种子,作为全局变量。我这样做是因为我认为对 rand_r 的调用需要访问一个静态的、不变的内存位置。
这是执行此操作的正确方法吗?或者我需要每个线程 不同的 整数。这会导致我的线程中出现任何竞争条件吗?生成的随机数怎么样 -- 每次都会不同吗?
编辑 1: 好吧,这个问题的答案基本上是不正确。每个线程都需要一个 unique 种子整数。例如,这可以来自 time() 或 p_thread_self() id。我仍然对如何准确地实现这一点感到困惑,但我会继续努力并报告回来。现在我决定使用 p_thread_self 作为每个线程的种子。
非常感谢您抽出时间来 look/answer。
My confusion stems from the fact that if I want a different integer to be used for rand_r for each thread, then how can I do this? How can I have a different (ie. random) integer be used for each thread, if I can't create random integers?
这里需要使用线程专用变量。所以你可以使用这些方法。
pthread_setspecific() & pthread_getspecific()
这用于创建全局变量,但仍特定于每个线程(不共享):它们是特定于线程的全局变量。
这个例子有很好的例子
- 每个线程需要 1 个种子,而不是全局种子。
- 要为每个线程生成唯一的种子,请从主线程调用
time()
以获取第一个种子。然后对于每个新线程,将一个添加到当前种子以获得下一个种子。例如,如果time()
返回 100,则您的种子将为 100、101、102 等。您的主线程需要将种子作为参数的一部分传递给每个线程。
编辑:
- 如以下评论所示,您可以获取初始种子(上例中的
100
)并将其与线程 ID 混合(使用异或或加法)。这样你就不必将种子传递给每个线程。至于 only 使用线程 id 作为种子,那也可以。但是,在新的 运行 上,您可能会获得与之前的 运行 相同的线程 ID(取决于您的 OS 确定线程 ID 的方式)。因此,如果您不想依赖 OS 生成线程 ID 的方式,您仍应使用一些初始种子,例如时间。
在 C++11 中,您可以使用 std::random_device
在每个线程上简单地创建另一个独立的种子。这与您在单线程代码中所做的完全相同。然后您可以在 std::this_thread
.
thread::sleep()
#include <random>
#include <thread>
#include <chrono>
thread_local std::random_device rd; // used once only per thread to initialise RNG
thread_local std::mt19937 rng(rd()); // thread-specific RNG
std::uniform_int_distribution<int> uni(0,800); // guaranteed unbiased
// called possibly many times
std::this_thread::sleep_for(uni(rng)*std::chrono::microseconds);
特别是,没有必要(滥用)使用当前时间作为种子 and/or 其他相关种子。