Этот код печатает значение х около 5000, но не 10000, почему это так? - PullRequest
0 голосов
/ 06 декабря 2018

Этот код, который я написал, создает 2 потока и цикл for, который повторяется 10000 раз, но значение x в конце выходит около 5000 вместо 10000, почему это происходит?

#include<unistd.h>
#include<stdio.h>
#include<sys/time.h>
#include "omp.h"
using namespace std;
int x=0;
int main(){
    omp_set_num_threads(2);
    #pragma omp parallel for
        for(int i= 0;i<10000;i++){
            x+=1;
        }
    printf("x is: %d\n",x);
}

Ответы [ 3 ]

0 голосов
/ 06 декабря 2018

Причина в том, что когда несколько потоков обращаются к одной и той же переменной, может возникнуть условия гонки .Операция x + = 1 может быть понята как: x = x + 1. Таким образом, вы сначала читаете значение x, а затем записываете x + 1 в x.Когда два потока работают и работают с одним и тем же значением x, происходит следующее: Поток A считывает значение x, равное 0. Поток B считывает значение x, равное 0. Затем поток A записывает 0 + 1 в x,А затем поток B записывает 0 + 1 в х.И теперь вы пропустили одно приращение, а x равно 1 вместо 2. Решение этой проблемы может заключаться в использовании atomic_int .

0 голосов
/ 06 декабря 2018

Изменение одного (общего) значения несколькими потоками является условием гонки и приводит к неверным результатам.Если несколько потоков работают с одним значением, все они должны только читать значение.

Идиоматическое решение состоит в том, чтобы использовать сокращение OpenMP следующим образом

#pragma omp parallel for reduction(+:x)
for(int i= 0;i<10000;i++){
    x+=1;
}

Внутренне каждый поток имеет свой собственныйx и они добавляются вместе после цикла.

Использование атомарности является альтернативой, но будет работать значительно хуже.Атомарные операции более затратны сами по себе, а также очень вредны для кэшей.

Если вы используете атомарные операции, вы должны использовать атомарные элементы OpenMP, которые применяются к операции, а не к переменной.Т.е.

#pragma omp parallel for
for (int i= 0;i<10000;i++){
    #pragma omp atomic
    x+=1;
}

Вы не должны, как предполагают другие ответы, использовать атомарность C ++ 11.Их использование является явно неопределенным поведением в OpenMP.Подробнее см. в этом вопросе .

0 голосов
/ 06 декабря 2018

x не является атомарным типом и читается и записывается в разных потоках.(Думать, что int является атомарным типом, является распространенным заблуждением.)

Поэтому поведение вашей программы undefined .

Использование std::atomic<int> x; - это исправление.

...