concurrent_vector не работает внутри parallel_for (PPL)

ниже приведен пример рабочего кода ( parallel_for с использованием библиотеки параллельных шаблонов ( ppl )). Основная проблема здесь заключается в том, что sqr ‹ concurrent_vector > хранимые значения меняются при каждом выполнении, но этого не должно быть!

Я использовал ‹ concurrent_vector > для произвольного доступа, почему он не работает?

#include <iostream>
#include <ppl.h>
#include <concurrent_vector.h>

using namespace std;
using namespace concurrency;

const int a = 10, b = 30;

critical_section cs;

int main() {

    concurrent_vector< int > labels( a * b );

    concurrent_vector< int > sqr( 5 );

    // filling label vector
    for ( int y = 0; y < b; y++ ) {
        for ( int x = 0; x < a; x++ ) {

            if( x<2 && y>3 )
                labels[ a * y + x ] = 1;
            else if( x<30 && y<5 )
                labels[ a * y + x ] = 2;
            else if( x>5 && y>10 )
                labels[ a * y + x ] = 3;
            else if( x>2 && y>20 )
                labels[ a * y + x ] = 4;
        }
    }

    // printing
    for ( int y = 0; y < b; y++ ) {
        for ( int x = 0; x < a; x++ ) {

            cout << labels[ a * y + x ] << ", ";
        }
        cout << endl;
    }

    parallel_for ( 0, b, [ & ]( int y ) {
        for ( int x = 0; x < a; x++ ) {

            //cs.lock();  // when i used it's working but slow
            int i = labels[ a * y + x ];
            //cs.unlock();

            if ( i < 0 ) continue;

            sqr[ i ] ++;
        }
    } );

    for( int i=0; i<5; i++ )
        cout << sqr[i] << ", ";
    cout << "" << endl;

    system ("pause");

    return 0;
}

person user2055437    schedule 23.02.2013    source источник
comment
Метод parallel_for не гарантирует какой-либо определенный порядок выполнения. В отличие от последовательного цикла, некоторые индексы с более высокими значениями могут обрабатываться раньше некоторых индексов с более низкими значениями. (msdn.microsoft.com/en-us/library/gg663527.aspx #сек2).   -  person SChepurin    schedule 23.02.2013
comment
хорошо, но конец выполнения всех потоков, результат должен быть таким же. Количество меток ( 1, 2, 3 ) не меняется. Что я пропустил или должен перед кодом получить правильный результат?   -  person user2055437    schedule 23.02.2013
comment
Я думаю, если использование блокировки решает проблему, то вы ошибаетесь в этом предположении.   -  person SChepurin    schedule 23.02.2013
comment
вы правы, блокировка работает, но она убивает параллелизм для больших размеров массива. поэтому я ищу другие решения или перспективы   -  person user2055437    schedule 23.02.2013


Ответы (2)


Использование метода task_group::wait должно быть быстрее (поскольку вам не нужно каждый раз блокировать/разблокировать), и он может работать так, как вы ожидаете.

Этот метод блокирует текущую задачу до тех пор, пока задачи другой группы задач не завершат свою работу.

См. MSDN: Параллельные задачи.

Обновление: я провел несколько тестов синхронизации и, похоже, это не решение (помимо того, что оба они терпят неудачу при больших объемах ввода данных на моем двухъядерном процессоре). Это может быть ошибка «дизайна» в concurrent_vector, как в Intel TBB — tbb::concurrent_vector возвращает неправильный размер

person SChepurin    schedule 23.02.2013

Вы не используете какие-либо функции параллельного вектора, которые имеют отношение к параллелизму. На самом деле, вы можете заменить его стандартным вектором без разницы... Видимо, значения i перекрываются при каждом выполнении ядра. Нет абсолютно никакой гарантии, что одновременная запись в один и тот же элемент вектора будет синхронизирована. Поэтому вы получаете случайные результаты - это просто следствие гонки данных при неатомарной записи.

person Paul Michalik    schedule 12.10.2013