I have the following polymorphic interface:
struct service
{
virtual void connect(std::function<void>(bool) cb);
// Invoke 'cb' with 'true' on connection success, 'false' otherwise.
virtual ~service() { }
};
Some implementations of service
are synchronous:
struct synchronous_service : service
{
void connect(std::function<void>(bool) cb) override
{
cb(true);
}
};
Others are asynchronous:
struct asynchronous_service : service
{
void connect(std::function<void>(bool) cb) override
{
_thread_pool.post([this, cb]{ cb(true); });
}
};
I need to create a service
wrapper, which is a service
itself. This needs to be thread-safe and maintain some state under a mutex
:
struct wrapped_service : service
{
state _state;
std::mutex _mutex;
std::unique_ptr<service> _underlying;
void connect(std::function<void>(bool) cb) override
{
std::lock_guard<decltype(_mutex)> guard;
// update `_state`
_underlying->connect([this, cb]
{
std::lock_guard<decltype(_mutex)> guard;
// update `_state`
cb(true);
});
// update `_state`
}
}
If the _underlying->connect
call is always asynchronous, then std::mutex
will work fine. However, in the case that _underlying->connect
is synchronous, the program will freeze.
This can be solved by using std::recursive_mutex
instead of std::mutex
, but it's generally known that it is a code smell.
Is this a valid use case for an std::recursive_mutex
?
Or is the design flawed? Note that I have no control over the service
interface.
Aucun commentaire:
Enregistrer un commentaire