I've run into a problem which seems troubling to me. It seems I've found a situation that's easy enough to work-around, but that could lead to problems if a) I have a lapse in concentration while programming or b) somebody else starts implementing my interfaces and doesn't know how to handle this situation.
Here's my basic setup:
I've got an abstract class that I'm using as a generic interface to several data types. I've adopted the non-virtual public interface paradigm (Sutter, 2001) along with scoped locking to provide some thread safety. An example interface class would look something like this (I've left out details about scoped locking and the mutex implementation, as I don't think they're relevant):
class Foo
{
public:
A( )
{
ScopedLock lock( mutex );
aImp( );
}
B( )
{
ScopedLock lock( mutex );
bImp( );
}
protected:
aImp( ) = 0;
bImp( ) = 0;
}
It is then up to the user to implement aImp and bImp, which is where the problem comes in. If aImp performs some operation which uses bImp, it's extremely easy (and almost logical, in some sense) to do this:
class Bar
{
protected:
aImp( )
{
...
B( );
...
}
bImp( )
{
...
}
}
Deadlock. Of course, the easy solution to this is to always call the protected virtual functions rather than their public variants (replace B( ) with bImp( ) in the above snippet). But it still seems far to easy to hang myself if I make a mistake, or worse yet allow others to hang themselves.
Does anybody have some way to attempt to either stop an implementer of the abstract class from calling those public functions at compile-time, or otherwise help to avoid the deadlock solution?
Just for kicks, some mutexes allow for operation which will avoid deadlock problems. As an example, if I implement this using the windows functions EnterCriticalSection and LeaveCriticalSection, there's no issue. But I'd rather avoid platform specific functionality. I'm currently using boost::mutex and boost::shared_mutex in my scoped lock implementation, and as far as I've seen it doesn't attempt to avoid deadlock (which I think I almost prefer).