Concurrency and parallelism
CP.22
Never call unknown code while holding a lock (e.g., a callback)
Reason
If you don't know what a piece of code does, you are risking deadlock.
Example
void do_this(Foo* p)
{
lock_guard<mutex> lck {my_mutex};
// ... do something ...
p->act(my_data);
// ...
}
If you don't know what Foo::act does (maybe it is a virtual function invoking a derived class member of a class not yet written), it might call do_this (recursively) and cause a deadlock on my_mutex. Maybe it will lock on a different mutex and not return in a reasonable time, causing delays to any code calling do_this.
Example
A common example of the "calling unknown code" problem is a call to a function that tries to gain locked access to the same object. Such problem can often be solved by using a recursive_mutex. For example:
recursive_mutex my_mutex;
template<typename Action>
void do_something(Action f)
{
unique_lock<recursive_mutex> lck {my_mutex};
// ... do something ...
f(this); // f will do something to *this
// ...
}
If, as it is likely, f() invokes operations on *this, we must make sure that the object's invariant holds before the call.
Enforcement
- Flag calling a virtual function with a non-recursive
mutexheld - Flag calling a callback with a non-recursive
mutexheld