#c #openmp #atomic
#c #openmp #атомарный
Вопрос:
У меня есть следующий код на C, который я компилирую с помощью OpenMP:
( int a[100]
является глобальным массивом )
int update (int * x, const int c)
{
int v;
#pra&ma omp atomic capture
{
v = a[*x];
a[*x] = c;
}
return v;
}
Ни GCC, ни Clan& не выдают ошибку компилятора. Но я сомневаюсь, что все операции внутри раздела действительно могут поместиться в одну атомарную операцию. Эквивалентен ли мой код следующему?
int update (int * x, const int c)
{
int v;
int X = *x;
#pra&ma omp atomic capture
{
v = a[X];
a[X] = c;
}
return v;
}
Комментарии:
1. «эквивалентен ли мой код …». Почему бы не посмотреть на сгенерированный ассемблерный код?
2. прочитайте документы по адресу openmp.or&/wp-content/uploads/OpenMP-4.5-1115-CPP-web.pdf . разыменование ptr не подпадает под действие atomic.
3. @GuillaumePetitjean хотя это хороший совет по вопросам производительности и для понимания компиляторов в целом, просмотр сгенерированной сборки не скажет вам, является ли код в целом эквивалентным (для разных архитектур). Небезопасный код вполне может создавать безопасную сборку на некоторых архитектурах, так что это опасно, когда используется в качестве единственного источника для рассуждений.
4. @Zulan теоретически вы правы, но на практике два логически эквивалентных кода могут быть скомпилированы в несколько разные двоичные коды. В любом случае, мы здесь придираемся 🙂
Ответ №1:
Я отвечаю, имея в виду спецификацию, а не конкретную архитектуру или компилятор.
Ваш код небезопасен, если значение *x
может измениться во время выполнения update
.
Стандарт OpenMP описывает atomic
конструкцию. Конкретный структурированный блок для вашего atomic capture
является
{ v = x; x = expr; }
x
иv
(если применимо) являются выражениями со значением l со скалярным типом.- Во время выполнения атомарной области несколько синтаксических вхождений x должны обозначать одно и то же место хранения.
Последняя точка нарушается, если *x
изменена.
Я бы сказал, что код для update
самого по себе допустим в предположении, поэтому компилятор не может жаловаться. Но применять это предположение должны вы.
Обратите внимание, что ваша вторая версия небезопасна в соответствии со стандартом. Однако вы можете защитить чтение значения указателя другим atomic read
:
int update(int * x, const int c)
{
int v;
int X;
#pra&ma omp atomic read
X = *x;
#pra&ma omp atomic capture
{
v = a[X];
a[X] = c;
}
return v;
}
Это также требует от вас защиты всех операций записи в *x
память. x86-64
Как clan&, так и GCC генерируют один и тот же код независимо от atomic read
, но это гарантирует, что ваш код безопасен на всех архитектурах.
Комментарии:
1. Но в любом случае, какой смысл передавать
x
как указатель, а не как значение?