3

The code is as follows:

#include<omp.h>
#include<stdio.h>
#include<stdlib.h>

int main()
{
    unsigned int seed = 1;
    int n =4;
    int i = 0;
#pragma omp parallel for num_threads(4) private(seed)
    for(i=0;i<n;i++)
    {
        int temp1 = rand_r(&seed);
        printf("\nRandom number: %d by thread %d\n", temp1, omp_get_thread_num());
    }
    return 0;
}

The code output is:

Random number: 1905891579 by thread 0

Random number: 1012484 by thread 1

Random number: 1012484 by thread 2

Random number: 1012484 by thread 3

This is strange for me: why thread 0 has different number? But when I change n with a const number 4:

#include<omp.h>
#include<stdio.h>
#include<stdlib.h>

int main()
{
    unsigned int seed = 1;
    const int n =4;
    int i = 0;
#pragma omp parallel for num_threads(4) private(seed)
    for(i=0;i<n;i++)
    {
        int temp1 = rand_r(&seed);
        printf("\nRandom number: %d by thread %d\n", temp1, omp_get_thread_num());
    }
    return 0;
}

The code output is:

Random number: 1012484 by thread 2

Random number: 1012484 by thread 3

Random number: 1012484 by thread 0

Random number: 1012484 by thread 1

All threads have the same random numbers. I don't understand the reason that thread 0 has different number when n is not a const variable. Is there any one know this thing? Thanks a lot.

majestic
  • 33
  • 5
  • 1
    Are you sure this is a "c++" question? The include of #include seems to indicate you're writing "C" code. The random numbers are because you use the same "seed" for both runs. For C++ look here for random number generation : https://en.cppreference.com/w/cpp/numeric/random/random_device. In c++ also try to avoid printf (it's unsafe: https://stackoverflow.com/questions/64042652/is-printf-unsafe-to-use-in-c). – Pepijn Kramer Nov 15 '21 at 04:26
  • @PepijnKramer "The random numbers are [...] because you use the same "seed" for both runs." Are what? Identical? They are not, according to OPs quote of output. – Yunnosch Nov 15 '21 at 06:18
  • @Yunnosch In the first version of code, I use the same seed, but I get different random number for thread 0. This is strange. – majestic Nov 15 '21 at 06:28
  • @PepijnKramer In the first version of code, I use the same seed, but I get different random number for thread 0. This is strange – majestic Nov 15 '21 at 06:32
  • I know. Pepijn seemingly does not. – Yunnosch Nov 15 '21 at 06:32

2 Answers2

2

seed is declared private, so within loop it got no initialized value, more of, each instance may or may not have distinct value, use of its value is UB. You can use firstprivate to let private instance be initialized with original value.

#pragma omp parallel for num_threads(4) firstprivate(seed)

Also rand_r is not a standard function but a level 2 thread-safe POSIX function. Level 2 implies that rand_r is safe only if used on separate objects/sources of data which isn't the case here i you would use same seed counter. The order of thread being called is undetermined and unsynced in this case. Odder outputs are possible because any one of thread may chance to update value of seed before others.

Swift - Friday Pie
  • 12,777
  • 2
  • 19
  • 42
  • Then what should I use rather than rand_r?Can you show me the right code? Thank you very much. – majestic Nov 15 '21 at 06:59
  • @majestic you have to build thread-safe generator (which would result in consequential execution) or use separate generators for each thread but in that case there is problem of setting their starting values in a non-predetermined way. – Swift - Friday Pie Nov 15 '21 at 07:03
  • `seed` is declared as `private` so according to omp doc, each thread should have its own copy of seed from the original. There should not be any thread safety issues here, only a random seeding issue. It's still not clear, in this context, how the thread 0 could generate a different output in the first case – Guillaume Gris Nov 15 '21 at 07:50
  • @GuillaumeGris hm, I believed such use is incorrect. If `seed` is `private` for each thread, in that case `seed` isn't initialized.. well and reaction to `const int n` is a fluke and result of UB, on a different system behaviour quite opposite. – Swift - Friday Pie Nov 15 '21 at 08:01
  • @majestic: If you're indeed using C++, check out ``. C++ random number generators are objects, and therefore you can have multiple identical RNGs. – MSalters Nov 15 '21 at 08:09
  • @MSalters I try GSL(which is thread-safe) to generate random numnber, therefore I can have multiple identical random number. – majestic Nov 15 '21 at 08:17
  • @Swift-FridayPie I try GSL(which is thread-safe) to generate random numnber, therefore I can have multiple identical random number. Thank you very much! – majestic Nov 15 '21 at 08:18
1

The problem is that the variable declared private is not initialized. If you add this line

  printf("thread %d seed %u \n", omp_get_thread_num(), seed);

before int temp1 = rand_r(&seed) you will get an output like this:

thread 3 seed 0 

Random number: 1012484 by thread 3 seed 2802067423

thread 0 seed 21850 

Random number: 2082025184 by thread 0 seed 2464192641

thread 2 seed 0 

Random number: 1012484 by thread 2 seed 2802067423

thread 1 seed 0 

Random number: 1012484 by thread 1 seed 2802067423

Repeating the runs, on my machine I see that the thread 0 gets always a different seed value, whereas the other threads have seed=0. In any case, this is UB due to an uninitialized variable.

francesco
  • 7,189
  • 7
  • 22
  • 49