Для получения триального ключа
заполните форму ниже
Team license
Enterprise license
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Бесплатная лицензия PVS-Studio для специалистов Microsoft MVP
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

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

Мне интересно попробовать плагин на:
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте папку
Spam/Junk и нажмите на письме кнопку "Не спам".
Так Вы не пропустите ответы от нашей команды.

>
>
OpenMP и исключения (exceptions)

OpenMP и исключения (exceptions)

16 Мар 2009

Мы продолжаем развивать наш статический анализатор VivaMP, и на этот раз хочется рассказать о диагностике ошибок, связанных с использованием исключений (exception) языка Си++ в параллельных регионах (parallel regions).

Поддержка VivaMP была прекращена в 2014 году. По всем возникшим вопросам вы можете обратиться в нашу поддержку.

Под параллельным регионом имеются виду фрагмент программы, который делится на параллельно выполняемые нити. Параллельно выполняемые нити формируют такими директивами OpenMP как for и sections.Использовать исключения внутри параллельных регионов можно. Но исключения не должны покидать эти параллельные регионы. Исключения должны быть пойманы и обработаны внутри параллельного региона с использованием конструкций try/catch. Если исключение выйдет за приделы параллельного региона, то это приведет к сбою и скорее всего к аварийному завершению программы. Рассмотрим пример некорректного кода:

#pragma omp parallel for num_threads(4)
for(int i = 0; i < 4; i++)
{
  //...
  throw 1;
}

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

size_t errCount = 0;
#pragma omp parallel for num_threads(4) reduction(+: errCount)
for(int i = 0; i < 4; i++)
{
  try {
    //...
    throw 1;
  }
  catch (...)
  {
    ++errCount;
  }
}
if (errCount != 0)
  throw 1;

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

Дополнительная сложность состоит в том, что исключение может вызвать не только ваш код, в котором вы напишите throw. Исключения могут быть сгенерированы и в используемых вами функциях или операторах выделения памяти. Рассмотрим следующий, на первый взгляд безобидный пример:

#pragma omp parallel for num_threads(4)
for(int i = 0; i < 4; i++)
{
  float *ptr = new float[10000];
  delete [] ptr;
}

Такой код может годами надежно работать, а может привести к аварийному завершению программы, если в какой-то момент оператор 'new' не сможет выделить объем необходимой памяти. Согласно стандарту языка Си++ оператор new выбрасывает исключение std::bad_alloc если не может выделить необходимый объем памяти. Такой подход позволяет не проверять, выделена ли необходимая память, как это делается в случае использования функции malloc, а сразу начать работу с ней. Если же память не выделена, то программа обработает эту ситуацию в нужном месте. В случае с параллельным регионом необходима дополнительная работа, чтобы корректно обработать ошибку выделения памяти внутри самого региона. Исправленный пример:

#pragma omp parallel for num_threads(4) reduction(+: errCount)
for(int i = 0; i < 4; i++)
{
  try {
    float *ptr = new float[10000];
    delete [] ptr;
  }
  catch (std::bad_alloc &)
  {
    //process error
  }
}

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

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

V1301. The 'throw' keyword cannot be used outside of a try..catch block in a parallel section

V1302. The 'new' operator cannot be used outside of a try..catch block in a parallel section.

V1303. The FOO function which throws an exception cannot be used in a parallel section outside of a try..catch block.

Диагностическое сообщение V1301 укажет на ошибку в первом примере, а V1302 диагностирует ошибки вызова оператора 'new' вне обработчика исключений. С V1303 все немного сложнее. Сейчас анализатор VivaMP будет предупреждать только о вызове функций, явно помеченных как бросающих исключения, то есть:

void MyThrowFoo() throw(...) { }

Функции не отмеченные "throw(...)" тоже могут бросать исключения, но они не диагностируются как опасные. Этот шаг сделан сознательно, чтобы уменьшить количество лишних диагностических сообщений. Ведь получится, что любой вызов функции в параллельной секции, неэкранированный конструкцией try/catch будет опасным. Хотя именно так оно и есть, но польза от такого количества диагностических сообщений сомнительна. Но возможно именно так себя в дальнейшем будет вести себя анализатор VivaMP в режиме "pedantic mode". И тогда безопасными, буду считать функции, явно помеченные, как не выбрасывающие исключений:

void MyNotThrowFoo() throw() { }

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

#pragma omp parallel num_threads (4)
{
    try {
        if (omp_get_thread_num ()  ==  0) {
            throw CException();
        }
        #pragma omp barrier
    }
    catch(CException &) {
    }
}

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

Дополнительная литература

Последние статьи:

Опрос:

Популярные статьи по теме
Как Apple и другие крупные компании настиг программный баг

Дата: 09 Ноя 2022

Автор: Ульяна Гришина

Сегодня мы отобрали свежие случаи программных ошибок, чтобы вы могли немного отвлечься и, возможно, узнать что-то новенькое. Если вам интересно узнать, как программисту удалось сломать Интернет по вс…
Единороги компании PVS-Studio

Дата: 30 Авг 2022

Автор: Андрей Карпов

Скорее всего вы перешли на эту статью, заинтересовавшись одним из наших рисунков единорогов. Приятно видеть ваш интерес. Сейчас мы расскажем, почему рисуем этих единорогов, что они означают и чем воо…
Обрабатывать ли в PVS-Studio вывод других инструментов?

Дата: 26 Май 2022

Автор: Андрей Карпов

Анализатор PVS-Studio умеет "схлопывать" повторяющиеся предупреждения. Предоставляет возможность задать baseline, что позволяет легко внедрять статический анализ в legacy-проекты. Стоит ли предостави…
15000 ошибок в открытых проектах

Дата: 24 Май 2022

Автор: Андрей Карпов

Количество багов в нашей коллекции перевалило за отметку 15000. Именно такое количество ошибок обнаружила команда PVS-Studio в различных открытых проектах. Особенно интересно, что это всего лишь побо…
Комментарии в коде как вид искусства

Дата: 04 Май 2022

Автор: Сергей Хренов

Приветствую всех программистов, а также сочувствующих. Кто из нас хотя бы раз в жизни не оставлял комментарии в коде? Был ли это ваш код, а может, чужой? Что за комментарии вы написали: полезные или …

Комментарии (0)

Следующие комментарии
Unicorn with delicious cookie
Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо