Я хочу избежать состояния гонки в параллельном коде. Проблема в том, что мой класс содержит несколько глобальных переменных, скажем, просто одну x
для простоты, а также цикл for
, который я хочу сделать параллельным. Фактический код также имеет метод, который принимает указатель на класс, в данном случае сам в качестве аргумента, для доступа к еще большему количеству глобальных переменных. Так что может иметь смысл сделать весь экземпляр threadprivate.
Я использую OpenMP. MWE составляет
#include <iostream>
#include <omp.h>
class lotswork {
public:
int x;
int f[10];
lotswork(int i = 0) { x = i; };
void addInt(int y) { x = x + y; }
void carryout(){
#pragma omp parallel for
for (int n = 0; n < 10; ++n) {
this->addInt(n);
f[n] = x;
}
for(int j=0;j<10;++j){
std::cout << " array at " << j << " = " << f[j] << std::endl;
}
std::cout << "End result = " << x << std::endl;
}
};
int main() {
lotswork production(0);
#pragma omp threadprivate(production)
production.carryout();
}
Мой вопрос: как я могу это сделать? Использование ключевого слова threadprivate
возвращает следующее сообщение об ошибке компилятора:
error: ‘production’ declared ‘threadprivate’ after first use
Я думаю, что эта проблема компилятора здесь еще не была решена :
Это подводит нас к тому, почему я использовал компилятор Intel. Visual Studio 2013 as
а также g ++ (4.6.2 на моем компьютере, Coliru (g ++ v5.2), область программирования
(g ++ v4.9.2)) разрешать только типы POD (источник). Это указано как ошибка
в течение почти десятилетия и до сих пор не полностью решены. Визуальный
Ошибка студии: C3057: globalClass: динамический
инициализация символов 'threadprivate' в настоящее время не поддерживается
и ошибка, заданная g ++, является ошибкой: объявлено 'globalClass'
'threadprivate' после первого использования Компилятор Intel работает с классами.
К сожалению, у меня нет доступа к компилятору Intel, но я использую GCC 8.1.0. Я провел небольшое предварительное исследование и нашел обсуждение этого здесь , но этот путь остыл, десять лет назад. Я задаю этот вопрос, потому что несколько человек имели проблемы с этим и решили их, либо объявив указатель класса как здесь , либо предложив ужасные обходные пути . Последний подход кажется ошибочным, потому что указатель обычно объявляется как константа, но тогда у нас есть threadprivate
указатели, в то время как экземпляр все еще используется совместно.
Попытка решения
Я считаю, что могу использовать ключевое слово private
, но не уверен, как это сделать со всем экземпляром класса, хотя я бы предпочел ключевое слово threadprivate
. Пример, аналогичный моему выше, на котором я смоделировал мой MWE, также обсуждался в главе 7, рис. 7.17 в этой книги , но без решения. (Я хорошо осведомлен о состоянии гонки и о том, почему это проблема.)
При необходимости я могу подтвердить, что вывод вышеуказанной программы без каких-либо дополнительных ключевых слов является недетерминированным.
Еще одна попытка решения
Теперь я подумал о решении, но по какой-то причине оно не скомпилируется. С точки зрения безопасности потоков и логической точки зрения моя проблема должна быть решена с помощью следующего кода. Тем не менее, должна быть какая-то ошибка.
#include <iostream>
#include <omp.h>
class lotswork : public baseclass {
public:
int x;
int f[10];
lotswork(int i = 0) { x = i; };
void addInt(int y) { x = x + y; }
void carryout(){
//idea is to declare the instance private
#pragma omp parallel firstprivate(*this){
//here, another instance of the base class will be instantiated which is inside the parallel region and hence automatically private
baseclass<lotswork> solver;
#pragma omp for
for (int n = 0; n < 10; ++n)
{
this->addInt(n);
f[n] = x;
solver.minimize(*this,someothervariablethatisprivate);
}
} //closing the pragma omp parallel region
for(int j=0;j<10;++j){
std::cout << " array at " << j << " = " << f[j] << std::endl;
}
std::cout << "End result = " << x << std::endl;
}
};
int main() {
lotswork production(0);
#pragma omp threadprivate(production)
production.carryout();
}
Таким образом, этот код, основанный на определениях, должен добиться цели, но каким-то образом он не компилируется. Может кто-нибудь помочь мне собрать этот код вместе, чтобы он достиг желаемой безопасности потока и компилировал, соблюдая ограничение, что threadprivate не подходит для людей, не являющихся разработчиками Intel? Заранее большое спасибо за помощь.