Musicode
Musicode

Reputation: 661

Correct way to use rand_r for multithreaded programs in C/C++

So, I need some help with multithredding in C++. I would like to have my multiple threads call the function usleep with a random number below 800. However, from my understanding, rand_r must be seeded with a different integer in each thread.

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?

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
    }
}

I have the static integers producerseed and consumerseed defined at the top of the program, as global variables. I did it this way because I thought that the calls to rand_r needed to access a static, non-changing memory location.

Is this the correct way to do this? Or do I need different integers for each thread. Will this result in any race conditions in my threads? What about the random number generated -- will it be different every time?

Edit 1: Okay, so the answer to that question was basically that it is incorrect. You need a unique seed integer for each thread. This can come from, for example, time() or the p_thread_self() id. I'm still confused as to how to implement this exactly, but I will work on it and report back. Right now I decided to use p_thread_self as the seed for each thread.

Thank you so much for taking the time to look/answer.

Upvotes: 4

Views: 9787

Answers (3)

Walter
Walter

Reputation: 45414

In C++11, you could simply create another independent seed on each thread using std::random_device. This is exactly the same as you would do in single-threaded code. You can then call thread::sleep() on std::this_thread.

#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);

In particular, there is no need to (ab)use the current time as seed and/or other correlated seeds.

Upvotes: 4

JS1
JS1

Reputation: 4767

  1. You need 1 seed per thread, not a global seed.
  2. To generate a unique seed per thread, call time() from the main thread to get the first seed. Then for each new thread, add one to the current seed to get the next seed. For example, if time() returned 100, your seeds would be 100, 101, 102, etc. Your main thread would need to pass the seed to each thread as part of the arguments to the thread.

Edit:

  1. As the comments below showed, you can take the initial seed (100 in the example above) and mix it with the thread id (using xor or addition). That way you don't have to pass the seed to each thread. As far as only using the thread id as a seed, that would work also. However, on a new run, you might get the same thread ids as a previous run (depending on how your OS determines thread ids). So if you don't want to depend on how your OS generates thread ids, you should still use some initial seed such as the time.

Upvotes: 1

Jeegar Patel
Jeegar Patel

Reputation: 27210

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?

Here you need to use thread specific variable. So you can use these method.

pthread_setspecific() & pthread_getspecific()

This is used to create variables that are global, but still specific to each thread (not shared): They are thread-specific global variables.

This examples has good example of https://stackoverflow.com/a/15101240/775964

Upvotes: 0

Related Questions