параллельная для: поток не может присвоить значение - PullRequest
0 голосов
/ 26 октября 2018

У меня есть цикл for, распараллеленный OpenMP . Я хочу, чтобы параллельные потоки заполняли std::vector<bool> из falses trues. Каждый поток должен писать в свою собственную запись вектора. Но иногда одно назначение не удается. Как это может произойти?

    int size = 10;
    std::vector<bool> vec(10);       // all entries contain false

#pragma omp parallel for
    for (int i = 0; i < size; ++i)
       vec[i] = true;                // sometimes this assignment fails for a thread

Вектор может выглядеть так: true true true true false true true true true true

Ответы [ 3 ]

0 голосов
/ 27 октября 2018

Проблема связана с тем, как хранится std::vector<bool>.Он разработан для экономии пространства и хранит элементы в отдельных битах, а не в байтах.Это означает, что присвоения vec[0], vec[1], ... vec[7] все записывают в один и тот же байт в памяти.Поскольку у вас есть несколько потоков, записывающих по одному и тому же адресу (на самом деле это будет последовательность чтения-изменения-записи), существует условие состязания.Это может привести к тому, что запись одного потока будет «отменена» записью более позднего потока.

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

При выполнении основной базовой операции (установка памяти в значение true) просто закодируйте ее как стандартныйне OMP однопотоковый цикл.Компилятор сможет оптимизировать его до чего-то разумно производительного.

0 голосов
/ 27 октября 2018

Согласно стандарту, все стандартные контейнеры обязаны избегать гонок данных, когда содержимое содержимого объекта в разных элементах в одном и том же контейнере изменяется одновременно. За исключением std::vector<bool>. 1201ProgramAlarm объясняет почему.

std::vector<bool> печально известен по многим вопросам - самое простое решение - использовать вместо него std::vector<char>. Если вы сделаете это, ваша программа будет в порядке, хотя вы не должны ожидать повышения производительности от использования OpenMP в этом конкретном случае.

0 голосов
/ 27 октября 2018

мой openmp ржавый, но на ум приходит #pragma omp flush [(list)]

директива flush в openmp может использоваться для идентификации точки синхронизации , которая определяется как точка выполнения программы, где исполняющий поток должен иметь согласованное представление о памяти. Для согласованного представления памяти предъявляются требования 2 : все операции чтения / записи памяти до и после Директива сброса должна выполняться либо до или после . это часто называют забором памяти . Страница 163, параллельное программирование в openmp Чандрой, Дагумом, Кором, Майданом, Макдональдом, Меноном; 2001

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

с очень небольшим количеством отправленного кода, и я не знаю, как и когда вы проверяете vec[i], так что это будет мое первое предположение ... а затем проверка версий операционной системы linux, компилятора C и задействованы версии openmp ...

но я не ожидаю, что обновление ОС, обновление компилятора или обновление версии openmp исправят то, что вы испытываете, скорее всего, ваш код

очень похоже на то, что происходит в стандартном C, когда вы делаете printf("hello") без следующего fflush(stdout), когда вы делаете , а не do printf("hello\n"). \n приводит к тому, что внутренняя очистка происходит в большинстве всех систем, что считается само собой разумеющимся.

...