I'm wondering if it is safe to throw an C++ exception inside an OMP critical section.
#pragma omp critical (my_critical_section)
{
...
throw my_exception("failed")
...
}
g++ does not complain. I'm puzzled because it complains about return
statements inside the critical section. It returns the error: invalid exit from OpenMP structured block
when I write
#pragma omp critical (my_critical_section)
{
...
return;
...
}
So, why is it OK to leave the critical section with an exception, but it is not OK to leave it with a return statement?
Purpose. The omp critical directive identifies a section of code that must be executed by a single thread at a time.
Use OpenMP critical sections to prevent multiple threads from accessing the critical section's code at the same time, thus only one active thread can update the data referenced by the code. Critical sections are useful for a non-nested mutex.
Specifies that only the main thread should execute a section of the program. critical. Specifies that code is only executed on one thread at a time. barrier. Synchronizes all threads in a team; all threads pause at the barrier, until all threads execute the barrier.
No, it is not OK to leave a critical section with exceptions. g++
does not complain in this case but it silently inserts an implicit try/catch
around the block of the critical section. For example the following code:
#pragma omp critical (my_crit)
{
throw 3;
}
gets lowered by the OpenMP processor of GCC 4.7 into:
#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);
Reaching the implicit built-in catch-all handler <<<eh_must_not_throw (terminate)>>>
results in quite ungraceful termination:
terminate called after throwing an instance of 'int'
Abort trap: 6
The implicit try/catch
is inserted regardless of the presence of an outer try/catch
construct, i.e. the exception would never ever leave the critical
section.
The OpenMP standard mandates, that if an exception is thrown within most OpenMP constructs (parallel
, section
, master
, single
, for
, critical
, task
, etc.), execution must resume within the same construct and that the same thread must catch the exception. Violation of this restriction leads to non-conformant OpenMP code and g++
simply enforces the conformance by inserting try/catch
blocks with termination handlers inside all such constructs.
As for the error when a return
statement is present, OpenMP defines a strcutured block in C/C++ as:
For C/C++, an executable statement, possibly compound, with a single entry at the top and a single exit at the bottom, or an OpenMP construct.
and also (for all languages):
The point of exit cannot be a branch out of the structured block.
Obviously return
constitutes a branch ouf of the block, different from simply falling of the bottom of the block.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With