【问题标题】:Multithreading in c using a thread safe random numbersc语言中的多线程使用线程安全随机数
【发布时间】:2014-12-05 00:38:15
【问题描述】:

我一直试图让它通过 valgrind 泄漏检查,并传入 20 亿个随机数并在线程之间划分它们。一旦我得到 10 亿个随机数,我就会不断遇到段错误。我在哪里分配错误或我做错了什么?

struct thread
{
    long long int threadID; //The thread id
    long long int operations; //The number of threads
};

void *generateThreads(void *ptr)
{
    struct thread *args = ptr;
    struct random_data *rdata = (struct random_data *) calloc(args->operations*64,sizeof(struct     random_data));
    char *statebuf = (char*) calloc(args->operations*64,BUFSIZE);
    long long int i;
    int32_t value;

    for(i = 0; i < args->operations; i++)
    {       
        initstate_r(args->threadID,&statebuf[i],BUFSIZE,&rdata[i]);
        random_r(rdata,&value);
    }

    if(DEBUG > 1)
        printf("I am thread %lld with thread id %X\n", args->threadID, (unsigned int) pthread_self());

    free(rdata);
    free(statebuf);
    pthread_exit(NULL);
}

int main(int argc, char **argv)
{
    long long int numRandoms;
    long long int numThreads;
    double timeStart = 0;
    double timeElapsed = 0;
    pthread_t *tid;
    struct thread args;

    if (argc != 3)
    {
         fprintf(stderr, "Usage: %s <Number of Randoms> <Number of Threads>\n" ,argv[0]);
         exit(1);
    }

   /* Assign the arg values to appropriate variables */
   sscanf(argv[1],"%lld",&numRandoms); /* lld for long long int */
   sscanf(argv[2],"%lld",&numThreads); /* lld for long long int */

   /* Number of threads must be less than or equal to the number of random numbers */
   if(numRandoms < numThreads)
   {
       fprintf(stderr,"Number of threads must be less than or equal to the number of random numers.\n");
       exit(1);
   }

   /*Start*/
   long long int i;
   args.operations = numRandoms/numThreads;
   timeStart = getMilliSeconds();
   tid = (pthread_t *) calloc(numThreads,sizeof(pthread_t));

   /* value is the thread id, creating threads */
   for(i = 0; i < numThreads; i++)
   {
       args.threadID = i;
       pthread_create(&tid[i],NULL,generateThreads,(void *) &args);
   }

   /* Joining the threads */
   for(i = 0; i < numThreads; i++)
   {
       pthread_join(tid[i],NULL);
   }

   /*Output*/
   timeElapsed = getMilliSeconds() - timeStart;
   printf("%lf\n",(double)(timeElapsed/1000.0));
   free(tid);
   fflush(stdout);
   exit(0);
}

【问题讨论】:

  • 您还没有向我们展示struct random_data 是什么,所以我们不知道它有多大。但是,calloc() 的参数很可能超过了您可以在计算机上分配为单个块的大小。另一个重要的问题:您是将其构建为 32 位还是 64 位程序?
  • 您不能即时生成随机数吗? rand() 返回一个 15 位数字,但您可以轻松获得更大的数字,例如 r = rand() + (rand()&lt;&lt;15);
  • (off-topic)对于线程数来说不是很长的过度杀伤力吗?我知道有些人想让他们的代码经得起未来的考验。
  • 为什么*64calloc 调用中?
  • 不知道initstate_rrandom_r 是什么,我不知道。你将不得不调试你的程序并试图找出它失败的地方。确保检查所有函数的返回值,例如calloc,并确保它们都没有返回 NULL 或错误值。

标签: c multithreading


【解决方案1】:

好的,我知道你想做什么了。问题是您复制的任何代码都使用了initstate_r 中的main 来设置所有线程的状态。它为每个线程调用一次 initstate_r 来为该线程设置 rng。但是您将该循环复制到每个线程中,因此您在每个线程中多次调用initstate_r,这是无用的。 *64 最初是为了让每个状态占用 64 个字节,以便将它们保持在单独的高速缓存行上。你可能指的是to this stackoverflow question

以下是您重写的函数以使其更有意义:

void *generateThreads(void *ptr)
{
    struct thread *args = ptr;
    struct random_data *rdata = calloc(1,sizeof(struct random_data));
    char statebuf[BUFSIZE];
    long long int i;
    int32_t value;

    initstate_r((int) pthread_self(),statebuf,BUFSIZE,rdata);
    for(i = 0; i < args->operations; i++)
    {
        random_r(rdata,&value);
        if(DEBUG > 1)
            printf("%d\n", value);
    }

    if(DEBUG > 1)
        printf("I am thread %lld with thread id %X\n", args->threadID, (unsigned int) pthread_self());

    free(rdata);
    pthread_exit(NULL);
}

顺便说一句,您将参数传递给线程的方式是错误的。您将相同的args 传递给每个线程,这意味着它们共享相同的args 结构,这意味着它们每个共享相同的args-&gt;threadID。您应该改为传递每个线程自己的 args 结构。

【讨论】:

    【解决方案2】:

    我对问题 link 的回答提供了线程安全的伪随机数生成器,该生成器使用 xorshift 算法为 __uint64/__uint128 整数设计。

    其他属性:

    • 共享可重入
    • 无锁
    • 线程安全
    • 超快
    • 从两种不同的熵源中播种

    【讨论】:

      猜你喜欢
      • 2019-08-09
      • 2020-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-07
      • 2011-08-14
      相关资源
      最近更新 更多