线程安全函数指针gsl monte carlo集成

时间:2016-02-19 14:58:57

标签: c++ thread-safety function-pointers gsl

我想使用gsl monte carlo集成库,而我目前遇到的线程安全问题到目前为止我无法解决。

我有一个静态函数 gsl_func_wrapper ,它包含了gsl(非成员函数指针)所需的正确类型。这将传递给 Integral 成员函数中的gsl monte carlo积分器。

class IntegralStrategyGSL2D: public IntegralStrategy2D {
  static Model2D *current_model;

  const gsl_rng_type *T;
  gsl_rng *r;
  gsl_monte_vegas_state *s;
  size_t calls;
  size_t maxcalls;

  static double gsl_func_wrapper(double *x, size_t dim, void *params) {
    return current_model->eval(x);
  }
...
}

IntegralStrategyGSL2D::IntegralStrategyGSL2D() :
    T(gsl_rng_default) {
  calls = 500;    // keep calls low at first
  maxcalls = 100000;
  gsl_rng_env_setup();
  r = gsl_rng_alloc(T);
  s = gsl_monte_vegas_alloc(2);
}

double IntegralStrategyGSL2D::Integral(Model2D *model2d, double xlow,
    double xhigh, double ylow, double yhigh, double precision) {
  current_model = model2d;
  double result, error;

  double xl[2] = { xlow, ylow };
  double xu[2] = { xhigh, yhigh }

  gsl_monte_function G = { &gsl_func_wrapper, 2, 0 };

  gsl_monte_vegas_init(s);

  while (true) {
    gsl_monte_vegas_integrate(&G, xl, xu, 2, calls, r, s, &result, &error);
    ...
  }
  ...
}

如果我使用1个线程运行,所有这些都有效,如果我使用多个线程,我会偶尔获得nan积分。由于gsl需要这个非成员函数指针,我现在还没有真正看到如何使这个线程安全...有人能指出我正确的方向吗? THX

编辑:我添加了将由gsl_func_wrapper调用的eval函数。

double GaussianModel2D::eval(const double *x) const {
  // see wikipedia definition

  double normalization = 1.0
        / (2.0 * M_PI * gauss_sigma_var1->getValue()
                * gauss_sigma_var2->getValue()
                * sqrt(1 - pow(gauss_rho->getValue(), 2.0)));

  double exp_value = exp(
        -(pow(x[0] - gauss_mean_var1->getValue(), 2.0)
                / pow(gauss_sigma_var1->getValue(), 2.0)
                + pow(x[1] - gauss_mean_var2->getValue(), 2.0)
                        / pow(gauss_sigma_var2->getValue(), 2.0)
                + 2.0 * gauss_rho->getValue()
                        * (x[0] - gauss_mean_var1->getValue())
                        * (x[1] - gauss_mean_var2->getValue())
                        / (gauss_sigma_var1->getValue()
                                * gauss_sigma_var2->getValue()))
                / (2.0 * (1 - pow(gauss_rho->getValue(), 2.0))));

  return gauss_amplitude->getValue() * normalization * exp_value;
}

EDIT2: 我根据Mike的要求添加了对Integral函数的调用。下面是进行Integral调用的两个相关代码块。我真的不明白为什么current_model变量的thread_local关键字解决了问题。虽然代码有点难看,但是current_model变量总是指向同一个model2d指针吗?因此,即使两个线程可能存在冲突写入,写入的值总是相同的,所以它应该无关紧要?或者

double smearing_probability = divergence_model->Integral(int_range, 1e-4);

double Model2D::Integral(const std::vector<DataStructs::DimensionRange &ranges,
    double precision) {
    return integral_strategy->Integral(this, ranges[0].range_low,
        ranges[0].range_high, ranges[1].range_low, ranges[1].range_high,
        precision);
}

2 个答案:

答案 0 :(得分:0)

假设在执行Integral的同一个线程中调用gsl_func_wrapper,您可以使用thread_local代替static作为current_model的存储类。

这将为每个线程提供一个单独的current_model变量。

答案 1 :(得分:0)

好的,所以我设法找出问题所在。这是变量

const gsl_rng_type *T; gsl_rng *r; gsl_monte_vegas_state *s;

是所有实例变量,因此所有线程都以相同的方式使用它们。如果我在Integral()函数中为每个线程单独创建其中的每一个,一切运行正常......