#pragma omp flush для обмена данными между потоками - PullRequest
3 голосов
/ 25 февраля 2011

Привет, я написал очень простой пример того, как использовать omp flush для обмена данными между производителями и потребителями. Я нашел странное поведение.

int a=-1;
int flag=1;
int count=0;
#pragma omp parallel  num_threads(2)
{ 
    int TID;
    TID=omp_get_thread_num();
#pragma omp sections 
    {

#pragma omp section /////////// Producer
        {

            for(int i=0; i<9;i++)
            {
                a=i;
#pragma omp flush(a)
                flag=1;
                printf("Producer a: %d  flag:%d  TID %d \n",a,flag,TID);

                while(flag)
                {

#pragma omp flush(flag)

                }

            }
            flag=2;
#pragma omp flush(flag)

        } // end producer

#pragma omp section  /////////// Consumer
        {
            while(1) {
                count++;

                flag=0;
                while(!flag)
                {
#pragma omp flush(flag)
                }
#pragma omp flush(a)
                printf("Consumer a: %d  Flag: %d  count %d TID %d \n",a,flag,count,TID);
                if (flag==2) break; // no more data

            } // end while(1)
        }// end consumer
    }// end sections

Использование этого очень простого кодавыдаст ошибочный вывод: Производитель a: 0 флаг: 1 TID 0
Производитель a: 1 флаг: 1 TID 0
Потребитель a: 1 Флаг: 1 счет 1 TID 1
Производитель a: 2 flag:1 TID 0
Потребитель a: 2 Флаг: 1 счет 2 TID 1
Производитель a: 3 флага: 1 TID 0
Потребитель a: 3 Флаг: 1 count 3 TID 1
Производитель a: 4флаг: 1 TID 0
потребитель a: 4 флаг: 1 счет 4 TID 1
производитель a: 5 флаг: 1 TID 0
потребитель a: 5 флаг: 1 счет 5 TID 1
производитель a: 6 флаг: 1 TID 0
потребитель a: 6 флаг: 1 счет 6 TID 1
производитель a: 7 флаг: 1 TID 0
потребитель a: 7 флаг: 1 счет 7 TID 1
Производитель a: 8 флаг: 1 TID 0
Потребитель a: 8 Флаг: 1 счет 8 TID 1
Потребитель a: 8 Флаг: 2 count 9 TID 1

Ошибка в том, что первый элемент данныхПроизведенное = 0 игнорируется потребителем.Если я просто инвертирую порядок секций, позволяя производителю быть потоком 1, тогда все в порядке ..... Флаг производителя: 0: 1 TID 1
Потребитель: 0: Флаг 1: 1 счет 1 TID 0
Производитель a: 1 флаг: 1 TID 1
Потребитель a: 1 Flag: 1 count 2 TID 0
.... В чем моя ошибка?

..... После интересного обсужденияс помощью Ejd (спасибо) код был отредактирован так:

int a=-1;
int flag=0;
int count=0;
#pragma omp parallel  num_threads(2)
{ 
int TID;
TID=omp_get_thread_num();
#pragma omp sections 
{
#pragma omp section  /////////// Consumer
    {

        while(1) {
            count++;
            if (flag) printf("Consumer a: %d  Flag: %d  count %d TID %d \n",a,flag,count,TID);
            flag=0;
            while(!flag)
            {
#pragma omp flush(flag)
            }
            if (flag==2) break; // no more data

        } // end while(1)
    }// end consumer

#pragma omp section /////////// Producer
    {
        for(int i=0; i<9;i++)
        {
            a=i;
            printf("Producer a: %d  flag:%d  TID %d \n",a,flag,TID);
            flag=1;
            while(flag)
            {
#pragma omp flush(flag,a)
            }

        }
        flag=2;
#pragma omp flush(flag)

    } // end producer


}// end sections    

Теперь это прекрасно работает.Спасибо!

1 Ответ

5 голосов
/ 25 февраля 2011

К сожалению, использование flush намного сложнее, чем кажется на первый взгляд.Даже специалисты по OpenMP испытывают затруднения, пытаясь использовать его правильно.Частично проблема в том, что заполнение списка плохо определено.В основном это разрешено перемещать, поэтому, если у вас есть последовательность вида:

a = ...
#pragma omp flush(a)
b = ...
#pragma omp flush(b)

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

В любом случае, лучший способ сделать то, что вы хотите, это использовать flush без списка и выполнять сброс после каждогонабор интересующей вас переменной и выполняйте очистку перед чтением каждой интересующей вас переменной.

Другая проблема заключается в том, что вы не выполняете передачу правильно.Вы не можете установить флаг в потребителе для производителя, чтобы сгенерировать другое число, пока потребитель фактически не использует произведенное значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...