Использование OpenMP и Eigen вызывает бесконечный цикл/тупик
Я решаю гораздо большую проблему и сталкиваюсь с ошибкой, когда пытаюсь использовать OpenMP для параллелизации некоторых циклов. Я воспроизвел проблему с помощью более простого кода ниже, который имитирует мой собственный код.
Проблема в том, что когда я запускаю программу, она будет случайным образом входить в какой-то бесконечный цикл/тупик (процессор 100%, но ничего не делает). Из того, что я могу сказать из моего тестирования, один из потоков пытается вычислить матрично-матричный продукт, но по какой-то причине не заканчивается.
Я знаю, что если вы включите OpenMP, Eigen будет распараллелить матрично-матричные продукты, используя OpenMP. Я также добавляю еще один параллельный цикл за пределами этого. Однако эта ошибка все же возникает, если я отключу Eigen-распараллеливание, определяя EIGEN_DONT_PARALLELIZE.
Я использую gcc версии 4.6.0 20101127 на MacOS 10.6.8 с Eigen 3.0.4.
Я не могу понять, что может быть неправильным...
#include <iostream>
#include <Eigen/Core>
using namespace std;
using namespace Eigen;
MatrixXd Test(MatrixXd const& F, MatrixXd const& G)
{
MatrixXd H(F.rows(), G.cols());
H.noalias() = F*G;
return H;
}
int main()
{
MatrixXd F = MatrixXd::Random(2,2);
MatrixXd G = MatrixXd::Random(2,2);
#pragma omp parallel for
for (unsigned int i = 0; i < 10000; ++i)
MatrixXd H = Test(F,G);
cout << "Done!" << endl;
}
Ответы
Ответ 1
После некоторой отладки, я думаю, проблема находится в Eigen. В файле src/Core/products/GeneralBlockPanelKernel.h
есть функция с именем manage_caching_sizes
, которая объявляет две статические переменные:
static std::ptrdiff_t m_l1CacheSize = 0;
static std::ptrdiff_t m_l2CacheSize = 0;
Изменение этого на:
static std::ptrdiff_t m_l1CacheSize = 0;
static std::ptrdiff_t m_l2CacheSize = 0;
#pragma omp threadprivate(m_l1CacheSize, m_l2CacheSize)
исправлена моя проблема.
Ответ 2
У меня была та же проблема, даже с самой последней версией Eigen (3.0.5). Я попробовал исправление, предложенное выше, и это невозможно с версией 3.0.5 из-за новых инициализаторов. Поэтому я сделал следующее изменение:
static std::ptrdiff_t m_l1CacheSize;
static std::ptrdiff_t m_l2CacheSize;
#pragma omp threadprivate(m_l1CacheSize, m_l2CacheSize)
if (m_l1CacheSize==0)
{
m_l1CacheSize = manage_caching_sizes_second_if_negative(queryL1CacheSize(),8 * 1024);
m_l2CacheSize = manage_caching_sizes_second_if_negative(queryTopLevelCacheSize(),1*1024*1024);
}
исправлена моя проблема.
Ответ 3
У меня была такая же проблема с использованием Microsoft Visual Studio 2010 SP1 PPL/parallel_for. Решение описано в
http://eigen.tuxfamily.org/dox/TopicMultiThreading.html
Использование Eigen в многопоточном приложении
В случае, если ваше собственное приложение многопоточно, а несколько потоки обращаются к Eigen, тогда вы должны инициализировать Eigen by вызывая следующую процедуру перед созданием потоков:
#include <Eigen/Core>
int main(int argc, char** argv)
{
Eigen::initParallel();
...
}
В случае, если ваше приложение распараллеливается с OpenMP, вы можете хотите отключить собственную собственную парализацию, как описано в предыдущем раздел.