#c #openmp #shared
#c #openmp #общие
Вопрос:
Я несколько новичок в OpenMP, но имею опыт работы с параллельной обработкой в целом. Я работал с boost::threads
раньше, и теперь я тестирую с openmp.
Проблема в том, что я не знаю, как обрабатывать общий доступ к данным, потому что я действительно не знаю, что openmp делает внутренне с разделяемыми объектами данных внутри параллельных циклов.
Что я делаю прямо сейчас (пока это работает): я считываю файлы с диска в память с помощью mmap. Я получаю указатель на символ после части карты памяти.
Теперь OpenMP может использовать этот указатель внутри параллельного цикла OpenMP for и обмениваться данными между потоками. Теперь я могу искать совпадения регулярных выражений внутри отображенного и общего файла с помощью нескольких потоков, проверяющих каждую строку по (довольно длинному) списку регулярных выражений.
Я сделал этот список (вектор, содержащий регулярное выражение) закрытым внутри цикла openmp, поэтому у каждого потока есть своя копия этого списка.
Здесь возникает проблема:
Чтобы значительно повысить производительность моего приложения, мне нужно иметь возможность удалять элементы (regex-) из этого вектора, как только они соответствуют строке.
Теперь всем другим активным потокам также необходимо удалить этот элемент из своего списка как можно скорее.
Итак, я сделал этот список общим объектом данных внутри цикла openmp, но теперь я получаю ошибки сегментации во время выполнения, когда я пытаюсь записать (vector.erase(item #)) в список.
С boost:: threads я бы просто использовал мьютекс для блокировки этого объекта во время его записи / чтения.
Но openmp, похоже, обрабатывает большую часть синхронизации сам, поэтому теперь мне интересно, каким был бы правильный подход к решению этой проблемы при использовании нового для меня openmp.
Комментарии:
1. У вас есть минимальный пример, демонстрирующий проблему?
Ответ №1:
Для синхронизации вы можете использовать #pragma omp critical
или вы можете использовать процедуры блокировки OpenMP ( omp_{init,set,unset,destroy}_lock
).
Преимуществами #pragma omp critical
являются простота и возможность игнорировать прагму, когда известно, что параллельная область выполняется одним потоком. Недостатками являются применимость только к одной параллельной области и глобальный эффект в пределах этой области: никакой другой поток не может выполнить какую-либо другую критическую секцию в регионе.
Процедуры блокировки OpenMP аналогичны большинству других доступных блокировок, например, в pthreads или Boost (исключая RAII). Вы инициализируете объект блокировки, затем используете его для защиты определенных критических разделов и уничтожаете, когда в этом нет необходимости. Эти блокировки могут использоваться для защиты доступа к данным из разных параллельных областей, для построения распределенной схемы блокировки и т.д.; Но всегда возникают определенные накладные расходы, и, безусловно, использование является более «волосатым» по сравнению с #pragma omp critical
.
Однако я бы поставил под сомнение дизайн параллельного решения. Удаление элемента из середины вектора делает все итераторы недействительными и перемещает элементы. Предположительно, удаление является редкой операцией (в противном случае, выбор вектора был бы сомнительным даже в последовательном коде, я думаю), но из-за вышеуказанных эффектов вы также должны защищать все чтения вектора, и это, вероятно, будет дорогостоящим. Блокировки чтения / записи могли бы принести некоторое облегчение, но они недоступны в OpenMP, поэтому вам нужно будет использовать либо интерфейсы, зависящие от платформы, либо стороннюю библиотеку.
Я думаю, что следующее потенциально будет работать лучше:
- Вы сохраняете векторы регулярных выражений закрытыми и добавляете общий вектор того же размера с флагами, которые указывают, является ли определенное регулярное выражение все еще допустимым или нет.
- Перед применением определенного регулярного выражения из частного вектора код проверяет в общем векторе, не было ли это регулярное выражение «стерто» каким-либо другим потоком. Если это было так, регулярное выражение пропускается.
- После нахождения соответствия код помечает элемент общего вектора, который соответствует текущему регулярному выражению, как «удаленный», так что с этого момента он будет игнорироваться.
В этой схеме существуют гонки за флагами чтения / записи: флаг может быть установлен в «удалено» в следующий момент, когда он был прочитан как «действительный» другим потоком. В результате два разных потока могут одновременно находить соответствие для одного и того же регулярного выражения. Однако я полагаю, что эта проблема существует в вашем текущем решении, где все контейнеры регулярных выражений являются частными, а также в решении с общим контейнером и блокировками или блокировками RW, если только блокировка, отличная от RW, не защищает также операцию с данным регулярным выражением. В случае, если несколько совпадений являются проблемой, все это следует пересмотреть.
Ответ №2:
Вы можете достичь этого, создав критический раздел.
#pragma omp critical
{
...some synchronized code...
}
Редактировать:
Удалена часть о ‘#pragma omp atomic’, поскольку она не может атомарно выполнять необходимые операции.
Комментарии:
1.
#pragma omp atomic
очень ограничен в том, какие выражения там разрешены. Приведенный вами пример не соответствует спецификации OpenMP. Я предлагаю вам удалить соответствующую часть из ответа.