A typicall application for this technique is locking and unlocking a mutex with the help of a so called guard:
extern mutex global_lock; static void f() { boost::details::pool::guard<mutex> g(global_lock); // g's constructor locks "global_lock" ... // do anything: // throw exceptions // return // or just fall through } // g's destructor unlocks "global_lock"
I have experienced enough C++ to know that there is no rule without an exception. In this case the exception is the exit function which breaks the RAII concept. The ISO C++ standard says in section 3.6.1.4:
Calling the function "void exit(int);" declared in <cstdlib> terminates the program without leaving the current block and hence without destroying any objects with automatic storage duration.So, for instance, if you call
exit()
from within the scope of a
guard object the mutex which is managed by this guard is not unlocked as the
destructor of the guard object is not called. You could argue now that the
program is going to exit anyway so who cares about a not-unlocked mutex? The
problem is that calling exit does not quit the program immediately. ISO C++,
section 12.4.10 says: Destructors are invoked implicitly for a constructed object with static storage duration at program termination.This means that if in the above example the mutex is a member of an object with static storage duration the destructor of the mutex is called while it is locked. If the destructor of the mutex class calls
pthread_mutex_destroy
you
run into the following problem: (phtread_mutex_destroy
manpage): Attempting to destroy a locked mutex results in undefined behavior.traps, traps, traps....
To make things worse the ISO C++ standard finishes section 3.6.1.4 with:
If exit is called to end a program during the destruction of an object with static storage duration, the program has undefined behavior.Thanks to Roker for digging out this issue.
No comments:
Post a Comment