|
23 | 23 |
|
24 | 24 | #if defined(ARMA_USE_FFTW3) |
25 | 25 |
|
| 26 | +struct fft_engine_fftw3_aux |
| 27 | + { |
| 28 | + #if (!defined(ARMA_DONT_USE_STD_MUTEX)) |
| 29 | + static inline std::mutex& get_plan_mutex() { static std::mutex plan_mutex; return plan_mutex; } |
| 30 | + #endif |
| 31 | + }; |
| 32 | + |
26 | 33 | template<typename cx_type, bool inverse> |
27 | 34 | class fft_engine_fftw3 |
28 | 35 | { |
@@ -74,7 +81,30 @@ class fft_engine_fftw3 |
74 | 81 | const int fftw3_flags = fftw3_flag_destroy | fftw3_flag_estimate; |
75 | 82 |
|
76 | 83 | arma_extra_debug_print("fft_engine_fftw3::constructor: generating 1D plan"); |
77 | | - fftw3_plan = fftw3::plan_dft_1d<cx_type>(N, X_work.memptr(), Y_work.memptr(), fftw3_sign, fftw3_flags); |
| 84 | + |
| 85 | + // only fftw3::execute() is thread safe, as per FFTW docs: |
| 86 | + // https://www.fftw.org/fftw3_doc/Thread-safety.html |
| 87 | + |
| 88 | + #if defined(ARMA_USE_OPENMP) |
| 89 | + { |
| 90 | + #pragma omp critical (arma_fft_engine_fftw3) |
| 91 | + { |
| 92 | + fftw3_plan = fftw3::plan_dft_1d<cx_type>(N, X_work.memptr(), Y_work.memptr(), fftw3_sign, fftw3_flags); |
| 93 | + } |
| 94 | + } |
| 95 | + #elif (!defined(ARMA_DONT_USE_STD_MUTEX)) |
| 96 | + { |
| 97 | + std::mutex& plan_mutex = fft_engine_fftw3_aux::get_plan_mutex(); |
| 98 | + |
| 99 | + const std::lock_guard<std::mutex> lock(plan_mutex); |
| 100 | + |
| 101 | + fftw3_plan = fftw3::plan_dft_1d<cx_type>(N, X_work.memptr(), Y_work.memptr(), fftw3_sign, fftw3_flags); |
| 102 | + } |
| 103 | + #else |
| 104 | + { |
| 105 | + fftw3_plan = fftw3::plan_dft_1d<cx_type>(N, X_work.memptr(), Y_work.memptr(), fftw3_sign, fftw3_flags); |
| 106 | + } |
| 107 | + #endif |
78 | 108 |
|
79 | 109 | if(fftw3_plan == nullptr) { arma_stop_runtime_error("fft_engine_fftw3::constructor: failed to create plan"); } |
80 | 110 | } |
|
0 commit comments