Ответ 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
представляет собой ветвь блока, отличную от простого падения нижней части блока.