В соответствии со спецификацией OpenMP (v4.0), следующая программа содержит возможные гонки данных из-за несинхронизированные чтения/записи i
:OpenMP атомные и неатомическое чтения/записи дают одинаковые инструкции по x86_64
int i{0}; // std::atomic<int> i{0};
void write() {
// #pragma omp atomic write // seq_cst
i = 1;
}
int read() {
int j;
// #pragma omp atomic read // seq_cst
j = i;
return j;
}
int main() {
#pragma omp parallel
{ /* code that calls both write() and read() */ }
}
Возможные решения, которые пришли на мой взгляд, приведены в коде в качестве комментариев:
- для защиты записи и чтения из
i
с#pragma omp atomic write/read
, - для защиты записи и читать:
i
с#pragma omp atomic write/read seq_cst
, - использовать
std::atomic<int>
вместоint
как типi
.
Вот компиляторы сгенерированные инструкции на x86_64 (с -O2
во всех случаях):
GNU g++ 4.9.2: i = 1; j = i;
original code: MOV MOV
#pragma omp atomic: MOV MOV
// #pragma omp atomic seq_cst: MOV MOV
#pragma omp atomic seq_cst: MOV+MFENCE MOV (see UPDATE)
std::atomic<int>: MOV+MFENCE MOV
clang++ 3.5.0: i = 1; j = i;
original code: MOV MOV
#pragma omp atomic: MOV MOV
#pragma omp atomic seq_cst: MOV MOV
std::atomic<int>: XCHG MOV
Intel icpc 16.0.1: i = 1; j = i;
original code: MOV MOV
#pragma omp atomic: * *
#pragma omp atomic seq_cst: * *
std::atomic<int>: XCHG MOV
* Multiple instructions with calls to __kmpc_atomic_xxx functions.
Что интересно, почему/лязг компилятор GNU не создает каких-либо специальных инструкций для #pragma omp atomic
пишет. Я ожидал бы аналогичных инструкций, как и для std::atomic
, то есть MOV+MFENCE
или XCHG
. Любое объяснение?
ОБНОВЛЕНИЕ
г ++ 5.3.0 производит MFENCE
для #pragma omp atomic write seq_cst
. Полагаю, это правильное поведение. Без seq_cst
он производит равную MOV
, что достаточно для атомарности без SC.
В моем файле Makefile произошла ошибка, g ++ 4.9.2 создает MFENCE
для записи атома CS. Извините, парни за это.
Clang 3.5.0 не реализует атомы OpenMP SC, благодаря чему Христо Илиев указал на это.
My GCC 4.9.2 генерирует «mfence» сразу после «movl $ 1, i (% rip)» для последовательной последовательной записи атома. –
Кроме того, Clang 3.5.0 поддерживает только регулярную последовательную последовательную атомизацию. Он даже не имеет полной поддержки OpenMP 3.1 - см. [Здесь] (http://wongmichael.com/2015/08/19/clang-3-7-will-have-full-openmp-3-1-support -followed-на-OpenMP-4 /). –
Ваш GCC 4.9.2 генерирует 'mfence' для атомарной записи OpenMP SC? То есть, когда 'i' имеет тип' int'? Мой GCC только для 'std :: atomic'. –