多线程c程序中的随机函数

pow*_*e97 3 c multithreading openmp

请看整个问题

我知道srand()应该只调用一次,但我的第二个代码段表明这不能解决问题!

我写的程序给了我输出,我无法弄清楚为什么会这样.代码段的不同更改会产生不同的输出.

代码目的:
代码用于omp简单地为3个线程运行一段代码.每个线程必须使用该rand()函数打印3个随机值.因此,共有9项产出.线程0是主线程/主程序的运行流程.线程1和线程2是在线程代码开始时创建的新线程.
代码:

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

int main()
{


     #pragma omp parallel num_threads(3)
    {
        srand(time(NULL));
        int i=0;
        for(i=0;i<3;i++)
        {
            printf("\nRandom number: %d by thread %d", rand(), omp_get_thread_num());
        }
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)


输出:

Random number: 17105 by thread 0
Random number: 30076 by thread 0
Random number: 21481 by thread 0
Random number: 17105 by thread 1
Random number: 30076 by thread 1
Random number: 21481 by thread 1
Random number: 17105 by thread 2
Random number: 30076 by thread 2
Random number: 21481 by thread 2
Run Code Online (Sandbox Code Playgroud)



但是如果我srand(time(NULL))在线程的代码之前保留,

 srand(time(NULL));  
 #pragma omp parallel num_threads(3)
{
    int i=0;
    ......
    ......(rest is same)
Run Code Online (Sandbox Code Playgroud)

输出是, 输出:

Random number: 16582 by thread 0
Random number: 14267 by thread 0
Random number: 14030 by thread 0
Random number: 41 by thread 1
Random number: 18467 by thread 1
Random number: 6334 by thread 1
Random number: 41 by thread 2
Random number: 18467 by thread 2
Random number: 6334 by thread 2
Run Code Online (Sandbox Code Playgroud)



问题和我的怀疑:

  • 通过将`srand`置于外部,所有线程对`rand()`的第一次调用给出了相同的随机数,所有第二次调用都给出了相同的随机数,同样也用于第三次调用.
  • 通过将`srand`放在里面,主线程的调用导致了与其他调用不同的随机数.但是,其中的两个新的其他线程为它们各自调用`rand()`提供了相同的随机数.

所以,

  • 这里到底发生了什么?为什么`srand()`函数的位置只对主线程(线程`0`)产生影响?
  • 为什么其他2个新线程总是输出相同的随机数,以便相应的调用`rand()`?
  • 这个`srand()`和`rand()`是如何连接的,导致这种异常?
  • 我尝试给每个线程提供等待间隔,以消除同时由不同线程调用`rand()`函数的可能性,这可能导致相同的随机数.但问题与以前完全一样.输出没有变化(只是输出发生的时间不同).

请帮我理解这一切......

Joh*_*ger 6

更新:已插入OP的枚举问题的直接答案.

这里到底发生了什么?

虽然某些版本的rand()函数在某种意义上可能是"线程安全的",但没有理由相信或期望在没有任何外部内存同步的情况下,rand()由不同线程执行的多个调用返回的值集将与集合相同由一个线程执行的相同调用次数返回的值.特别是,rand()维护在每次调用时修改的内部状态,并且没有任何内存同步,一个线程看不到由其他线程执行的内部状态的更新是完全合理的.在这种情况下,两个或更多个线程可以部分或完全生成相同的数字序列.

为什么srand()函数的位置只对主线程(线程0)产生影响?

唯一可以肯定的是,如果srand()它在并行块之外,那么它只由主线程执行,而如果它在内部则由每个线程单独执行.由于你的代码没有正确同步,每​​个案例的效果都无法从源代码中预测出来,因此我的下一条评论大多是推测性的.

假设time()使用其(仅)一秒精度,在每个线程中返回相同的值,放置srand()在并行区域内确保每个线程看到相同的初始随机数种子.如果他们没有看到彼此的更新,那么他们将生成相同的伪随机数序列.但是请注意,你既不能安全地依靠线程看到对方的更新,也不安全地依赖他们没有看到对方的更新.

srand()但是,如果将外部放在并行区域之外,使其仅由主线程执行,则还有其他可能性.如果OMP维护一个线程池,其成员已经在您进入并行部分之前已经启动,则可能是线程1和2根本无法看到线程0 srand()调用的效果,因此两者都继续使用默认种子.还有其他可能性.

为什么其他两个新线程总是为相应的调用输出相同的随机数rand()

无可置疑地说出来是不可能的.然而,我倾向于猜测,所涉及的线程都没有看到彼此对rand()内部状态的更新.

这是如何srand()rand()连挂,造成这种异常?

这两个功能密切相关.目的srand()是修改rand()内部状态("种子"它,因此"s"中的"s"),以便启动它在不同(但仍然是确定性的)点生成的伪随机数序列.


这个问题的解决方法与解决涉及多线程访问共享变量的任何问题的方法相同:通过应用同步.在这种情况下,最直接的同步形式可能是rand()使用互斥锁来保护呼叫.由于这是OMP代码,您最好的选择可能是使用OMP锁来实现互斥锁,因为将显式pthreads对象与OMP声明混合似乎很冒险.