c - OpenMP 任务的随机值生成器错误
问题描述
我正在尝试在使用 OpenMP 任务时开发基于蒙特卡洛方法计算 Pi 的微代码。看来我在该代码中遇到了一些麻烦。事实上,我的应用程序只是崩溃了,我得到了来自 gomp_barrier 函数的分段错误......
我不知道我的代码是否做错了,但我花了一点时间尝试调试它,但我什么也没找到。当我简单地使用随机值生成器删除 x 和 y 的计算时,代码运行良好......但是如果我添加对 rand_r 或 srand48_r 的调用,我就会遇到这个段错误。所以也许,我对这些功能的使用是错误的。有人有想法吗?
这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <inttypes.h>
#include <time.h>
#include <unistd.h>
#include "omp.h"
#define TRIALS_PER_THREAD 10E6
int main(int argc, char** argv)
{
uint64_t const n_test = TRIALS_PER_THREAD;
uint64_t i;
double pi = 0.;
int nb_threads = 2;
#pragma omp parallel shared(nb_threads)
{
#pragma omp master
nb_threads = omp_get_num_threads();
}
fprintf(stdout, "Nb threads: %d\n", nb_threads);
uint64_t* result = (uint64_t*)malloc(sizeof(uint64_t) * nb_threads);
for(i = 0; i < nb_threads; ++i)
{
result[i] = 0;
}
int nb_test_per_thread = 20;
#pragma omp parallel\
shared(result)\
firstprivate(n_test,nb_test_per_thread)
{
unsigned int seed;
struct drand48_data randBuffer;
seed = time(NULL) ^ omp_get_thread_num() ^ getpid();
srand48_r(seed, &randBuffer);
for(int k = 0; k < nb_test_per_thread; ++k)
{
#pragma omp task shared(result, seed, randBuffer)
{
uint64_t local_res = 0;
double x = 0., y = 0.;
for(i = 0; i < n_test; ++i)
{
drand48_r(&randBuffer, &x);// / (double)RAND_MAX;
drand48_r(&randBuffer, &y);// / (double)RAND_MAX;
local_res += (((x * x) + (y * y)) <= 1);
}
int tid = omp_get_thread_num();
result[tid] += local_res;
}
}
}
for(i = 0; i < nb_threads; ++i)
{
pi += result[i];
}
fprintf(stdout, "%ld of %ld throws are in the circle !\n", (uint64_t)pi, n_test*nb_test_per_thread*nb_threads);
pi *= 4;
pi /= (double)(n_test*nb_test_per_thread*nb_threads);
fprintf(stdout, "Pi ~= %f\n", pi);
return 0;
}
预先感谢您的帮助 !
解决方案
您的使用drand48_r(&randBuffer, &x);
具有竞争条件,因为每个 OpenMP 线程共享randBuffer
.
概要
#include <stdlib.h> int drand48_r(struct drand48_data *buffer, double *result); ...
...
属性
有关本节中使用的术语的解释,请参阅 attributes(7)。
┌──────────────────────────┬───────────────┬─────────────────────┐ │Interface │ Attribute │ Value │ ├──────────────────────────┼───────────────┼─────────────────────┤ │drand48_r(), erand48_r(), │ Thread safety │ MT-Safe race:buffer │ │lrand48_r(), nrand48_r(), │ │ │ │mrand48_r(), jrand48_r(), │ │ │ │srand48_r(), seed48_r(), │ │ │ │lcong48_r() │ │ │ └──────────────────────────┴───────────────┴─────────────────────┘
请注意ATTRIUBTES表中MT-Safe race:buffer
的。
根据属性(7)手册页:
`:identifier`
注释有时可能会跟在标识符后面,旨在将多个函数分组,例如,以不安全的方式访问数据结构,如
race
和const
...
由于数据竞争条件,多个并行调用drand48_r()
不能安全地共享相同的参数。buffer
推荐阅读
- ruby-on-rails - 在 Rails 中从一个应用程序调用控制器操作到另一个应用程序
- google-cloud-platform - 无法连接到 Google Cloud Platform 上的 ssh:
- r - 我想用 x, y 坐标创建一个 Dataframe 的高分辨率热图。来自足球比赛的数据
- javascript - 比较数据库表字段值,与单个数据库中的两个不同表
- django - 如何在django中实现搜索功能
- javascript - 为什么两个相同日期的 getTime 值不同
- python-3.x - Selenium:无法定位元素
- node.js - “Express”类型的值与“ServerOptions”类型没有共同的属性
- oracle - 使用 sql 查询获取 clob 字段中的每一行
- graphql - 既不是突变也不是查询的 Apollo/GraphQL 动作