OpenMP-ошибки
Продукт PVS-Studio содержит набор правил статического анализа, предназначенный для выявления ошибок в коде параллельных программ на языке C/C++/C++11, написанных с использованием технологии OpenMP.
Ранее этот набор правил поставлялся в виде отдельного решения под названием VivaMP. Сейчас статический анализатор VivaMP включен в состав программного продукта PVS-Studio. Теперь под названием VivaMP понимается соответствующий набор правил для поиска параллельных ошибок.
Набор специализированных правил VivaMP позволяет обнаружить в коде ряд ошибок приводящих к состоянию гонок, неопределенному поведению, неэффективному использованию процессорного времени и так далее. Основной сложностью обнаружения подобных дефектов на этапе тестирования является их нерегулярность проявления. Статический анализатор работает с исходным кодом и просматривает все пути возможного выполнения программы. Поэтому он может обнаружить некоторые из этих крайне редко проявляющихся ошибок. С другой стороны статический анализ не может обнаружить многое из того, что находят инструменты динамического анализа, такие как Intel Parallel Inspector. Не следует пытаться выбрать один подход к обнаружению параллельных ошибок. Здесь статический и динамический анализ хорошо дополняют другу друга.
Рассмотрим некоторые примеры параллельных ошибок, выявляемых PVS-Studio.
Необработанные исключения в параллельных секциях
#pragma omp parallel for
for (size_t i = 0; i != n; ++i) {
float *array = new float[10000];
delete [] array;
}
Этот код приведет к некорректному поведению программы и, скорее всего, к ее аварийному завершению, если произойдет ошибка выделения памяти.
Ошибка связана с бросанием исключения из параллельной секции. Согласно спецификации OpenMP, если вы используете исключения внутри параллельной секции, то все эти исключения должны быть обработаны внутри этой секции. Если вы используете внутри параллельной секции оператор new, то вы должны позаботиться о перехвате исключения, которое согласно стандарту языка Си++ будет сгенерировано при ошибке выделения памяти.
Ошибка, приводящая к возникновению состояния гонки
int a = 0;
#pragma omp parallel for num_threads(4)
for (int i = 0; i < 100000; i++) {
a++;
}
Состояние гонки возникает тогда, когда несколько потоков многопоточного приложения пытаются одновременно получить доступ к данным, причем хотя бы один поток выполняет запись. Состояния гонки могут давать непредсказуемые результаты, и зачастую их сложно выявить. Иногда последствия состояния гонки проявляются только через большой промежуток времени и в совсем другой части приложения. Кроме того, ошибки такого рода невероятно сложно воспроизвести повторно.
Крайне эффективным является выявление, по крайней мере, части таких ошибок с помощью статического анализа еще на этапе написания кода.
Инициализация статических переменных внутри параллельных секций
pragma omp parallel
{
static int st = Calc();
...
}
Статическая переменная начнет процесс инициализации сразу в нескольких потоках, что может привести к неопределенному результату. Необходимо использовать механизмы синхронизации, чтобы инициализировать переменную только в одном из потоков и при этом не дать другим потоком использовать ее до окончания инициализации.
Ошибка невнимательного использования директив OpenMP
void Foo() {
#pragma omp for
for (int i = 0; I < n; ++i)
...
Случайно забыто ключевое слово parallel. Цикл, вопреки ожиданиям программиста, будет выполняться только одним потоком.
Ошибка невнимательного использования одной из функций OpenMP
#pragma omp parallel
{
omp_set_num_threads(2);
...
}
Количество потоков нельзя переопределять внутри параллельной секции. Это приводит к ошибке во время выполнения программы и ее аварийному завершению.
Более подробно с различными примерами параллельных ошибок вы можете познакомиться в статье "32 подводных камня OpenMP при программировании на Си++" и "Неудачная попытка сравнить PVS-Studio (VivaMP) и Intel C/C++ ("Parallel Lint")".
Преимущества использования статического анализа для выявления дефектов в параллельных программах
Используемая в инструменте PVS-Studio методология статического анализа кода имеет существенные преимущества над другими видами анализа. Ошибки в параллельных программах обычно трудно воспроизводимы, и их трудно обнаружить в процессе отладки. Основное преимущество статического анализа заключается в отсутствие необходимости запуска приложений и независимости от аппаратной среды. Статический анализ позволяет охватить весь программный код. Процедура проверки кода не может как-либо повредить сам код. Процесс анализа полностью контролируется человеком, и именно он принимает решения о необходимости его модификации.
Инструмент PVS-Studio сопровождается большой базой знаний по разработке параллельных приложений кода (справочная система, статьи, примеры), которая позволит поднять уровень знаний программистов в области параллельного программирования.