Выброс исключения С++ внутри критического раздела omp

Мне интересно, можно ли исключить исключение С++ в критическом разделе OMP.

#pragma omp critical (my_critical_section)
{
    ...
    throw my_exception("failed")
    ...       
}

g++ не жалуется. Я озадачен, потому что он жалуется на утверждения return внутри критического раздела. Он возвращает ошибку: invalid exit from OpenMP structured block, когда я пишу

#pragma omp critical (my_critical_section)
{
    ...
    return;
    ...       
}

Итак, почему остается оставить критический раздел с исключением, но он не ОК, чтобы оставить его с помощью оператора return?

Ответы

Ответ 1

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

#pragma omp critical (my_crit)
{
   throw 3;
}

снижается с помощью процессора OpenMP GCC 4.7 в:

#pragma omp critical (my_crit)
__builtin_GOMP_critical_name_start (&.gomp_critical_user_my_crit);
try
  {
    D.20639 = __cxa_allocate_exception (4);
    try
      {
        MEM[(int *)D.20639] = 3;
      }
    catch
      {
        __cxa_free_exception (D.20639);
      }
    __cxa_throw (D.20639, &_ZTIi, 0B);
  }
catch
  {
    <<<eh_must_not_throw (terminate)>>>
  }
__builtin_GOMP_critical_name_end (&.gomp_critical_user_my_crit);

Достижение неявного встроенного обработчика catch-all <<<eh_must_not_throw (terminate)>>> приводит к довольно неуважительному завершению:

terminate called after throwing an instance of 'int'
Abort trap: 6

Неявный try/catch вставляется независимо от наличия внешней конструкции try/catch, т.е. исключение никогда не покидает раздел critical.

Стандарт OpenMP предусматривает, что если исключение выбрано в большинстве конструкций OpenMP (parallel, section, master, single, for, critical, task и т.д.), выполнение должно возобновиться в рамках одной и той же конструкции и что тот же поток должен поймать исключение. Нарушение этого ограничения приводит к несоответствию кода OpenMP и g++ просто обеспечивает соответствие, вставляя try/catch блоки с обработчиками завершения внутри всех таких конструкций.

Что касается ошибки, когда присутствует оператор return, OpenMP определяет строковый блок в C/С++ как:

Для C/С++ исполняемый оператор, возможно, составной, с одной записью сверху и одним выходом внизу или конструкцией OpenMP.

а также (для всех языков):

Точка выхода не может быть ветвью из структурированного блока.

Очевидно, что return представляет собой ветвь блока, отличную от простого падения нижней части блока.