2016-02-17 2 views
6

В соответствии со спецификацией 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() */ } 
} 

Возможные решения, которые пришли на мой взгляд, приведены в коде в качестве комментариев:

  1. для защиты записи и чтения из i с #pragma omp atomic write/read,
  2. для защиты записи и читать: i с #pragma omp atomic write/read seq_cst,
  3. использовать 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, благодаря чему Христо Илиев указал на это.

+0

My GCC 4.9.2 генерирует «mfence» сразу после «movl $ 1, i (% rip)» для последовательной последовательной записи атома. –

+2

Кроме того, 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 /). –

+0

Ваш GCC 4.9.2 генерирует 'mfence' для атомарной записи OpenMP SC? То есть, когда 'i' имеет тип' int'? Мой GCC только для 'std :: atomic '. –

ответ

1

Есть две возможности.

  1. Компилятор не обязан конвертировать код C++, содержащий гонку данных, в плохой машинный код. В зависимости от модели памяти устройства обычно используемые инструкции могут быть уже атомарными и когерентными. Возьмите тот же код на C++ в другую архитектуру, и вы можете начать видеть, что прагмы вызывают различия, которых не было на x86_64.

  2. В дополнение к потенциально может привести к использованию различных инструкций и/или дополнительные инструкции забора памяти, атомных прагмах (а std::atomic и volatile) также ограничивают собственный код переназначения оптимизаций компилятора. Они могут не применяться к вашему простому случаю, но вы наверняка заметили, что устранение общего подвыражения, включая вычисления подъема вне цикла, может быть затронуто.

+0

Я согласен, однако, что MOV «один не должен быть достаточным для последовательного согласованного хранилища атомов (см., например, [здесь] (https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html) или [лекцию Херба Саттера 0:35:00] (https://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-2-of-2)). Поэтому I ожидал бы 'XCHG' или' MFENCE' для '#pragma omp atomic write seq_cst'. –

+1

Однако, считая, что данные правильно выровнены, mov * * достаточно для простого атома (без seq_cst), так как в X86 разрыв не может произойти . (Все байты, составляющие значение, записываются атомарно mov). Без seq_cst атомная конструкция также не подразумевает OpenMP «flush». –

+0

@ Jim Cownie: Вы уверены в промывать? Из OpenMP Spec. 4.0: _ Область смыва ** со списком ** подразумевается в следующих местах: при входе и выходе из атомарной операции, выполняемой в ** не последовательно последовательной атомной области **, где список содержит только место хранения обозначается как x в соответствии с описанием синтаксиса атомной конструкции в Разделе 2.12.6 на стр. 127._ И: _ Область flush ** без списка ** подразумевается в следующих местах: ... При входе в и выход из атомной операции, выполняемой в последовательной последовательной атомной области ** ._ –