【问题标题】:Using FFTW in OOP with multithreading在具有多线程的 OOP 中使用 FFTW
【发布时间】:2021-06-09 23:42:55
【问题描述】:

考虑一个用于二维复数值数组的容器

#include <vector>
#include <array>

struct Array2D {
  typedef std::array<double, 2> complex;

  int X, Y;
  std::vector<complex> values;
};

还有一个使用FFTW 计算傅里叶变换的函数:

#include <fftw3.h>

void FourierTransform(const Array2D& source, Array2D *dest) {
  fftw_plan p = fftw_plan_dft_2d(source.X, source.Y, (fftw_complex*)source.values.data(), (fftw_complex*)dest->values.data(), FFTW_FORWARD, FFTW_ESTIMATE);
  fftw_execute(p);
  fftw_destroy_plan(p);
}

这不是一个最佳实现,因为它每次计算傅里叶变换时都会创建和销毁一个计划,但它方便且易于使用。但是,创建和销毁 FFTW 计划不是线程安全的(请参阅here),因此不应从不同的线程同时调用此函数。

问题:

  • 我的应用程序中有许多不同的数组,我需要计算傅里叶变换和
  • 在使用#pragma omp parallel for 并行化主循环和代码中我需要计算傅里叶变换的位置之间有几个函数调用。

#pragma omp parallel for 之前初始化所有这些数组以及 fftw 计划,然后将它们作为参数传递给后续函数会使代码很多不那么清晰。还有其他方法可以让我以线程安全的方式封装和隐藏 FFTW 函数调用吗?

【问题讨论】:

  • 旁白:你的演员表中有未定义的行为。你是reinterpret_casting std::array&lt;double, 2&gt; *fftw_complex*,这是无效的。你为什么不使用std::complex&lt;double&gt;_Complex

标签: c++ multithreading openmp fftw


【解决方案1】:

FFTW 文档的链接提供了一个答案,即确保对 FFTW 的不安全调用被序列化。它建议使用信号量来执行此操作,但由于您在 OpenMP 中,您可以使用 #pragma omp critical 来执行此操作,类似这样

    void FourierTransform(const Array2D& source, Array2D *dest) {
      fftw_plan p;
      #pragma omp critical (FFTW)
      {
        p = fftw_plan_dft_2d(source.X, source.Y, 
                             (fftw_complex*)source.values.data(),
                             (fftw_complex*)dest->values.data(), 
                             FFTW_FORWARD, FFTW_ESTIMATE);
      }
      fftw_execute(p);
      #pragma omp critical (FFTW)
      {
         fftw_destroy_plan(p);
      }
    }

我在那里使用了一个命名的临界区(名称为 FFTW),因此这些临界区不会减少与代码中任何其他临界区的并行性,而是相互保护。

更一般地说,提供相关函数的包装的、线程安全的版本并调用它们可能会更好,而不是未包装的。就像

static fftw_plan_p TS_fftw_plan_dft_2d(... arguments ... ) {
    fftw_plan p;
    #pragma omp critical (FFTW)
    {
        p = fftw_plan_dft_2d(... arguments ...);
    }
    return p;
}

然后,您只需在其余代码中调用 TS_fftw_foo 而不是 fftw_foo

如果你想变得更极端,你可以将所有这些包装器放入一个标题中(也将它们标记为内联),然后还有宏将相关的 FFTW 函数扩展为 TS_fftw 函数。然后包括你的标题就可以了。 不过,这更加晦涩和极端。只需包装您需要的功能可能更清楚发生了什么。

显然所有这些代码都未经测试和编译,但我希望你能明白。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-27
    • 1970-01-01
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    相关资源
    最近更新 更多