A rigor di termini, la domanda riguardava il controllo del blocco di std::mutex
direttamente. Tuttavia, se è consentito incapsularlo in una nuova classe, è molto semplice farlo:
class mutex :
public std::mutex
{
public:
#ifndef NDEBUG
void lock()
{
std::mutex::lock();
m_holder = std::this_thread::get_id();
}
#endif // #ifndef NDEBUG
#ifndef NDEBUG
void unlock()
{
m_holder = std::thread::id();
std::mutex::unlock();
}
#endif // #ifndef NDEBUG
#ifndef NDEBUG
/**
* @return true iff the mutex is locked by the caller of this method. */
bool locked_by_caller() const
{
return m_holder == std::this_thread::get_id();
}
#endif // #ifndef NDEBUG
private:
#ifndef NDEBUG
std::atomic<std::thread::id> m_holder;
#endif // #ifndef NDEBUG
};
Nota quanto segue:
- Nella modalità di rilascio, questo ha un sovraccarico pari a zero rispetto a
std::mutex
tranne possibilmente per la costruzione/distruzione (che non è un problema per gli oggetti mutex). - Il
m_holder
membro è accessibile solo tra l'acquisizione del mutex e il suo rilascio. Così il mutex stesso funge da mutex dim_holder
. Con ipotesi molto deboli sul tipostd::thread::id
,locked_by_caller
funzionerà correttamente. - Altri componenti STL, ad esempio
std::lock_guard
sono modelli, quindi funzionano bene con questa nuova classe.
std::unique_lock<L>
ha owns_lock
funzione membro (equivalente di is_locked
come dici tu).
std::mutex gmtx;
std::unique_lock<std::mutex> glock(gmtx, std::defer_lock);
void alpha(void) {
std::lock_guard<decltype(glock)> g(glock);
beta(void);
// some other work
}
void beta(void) {
assert(glock.owns_lock()); // or just assert(glock);
// some real work
}
MODIFICA: In questa soluzione, tutte le operazioni di blocco dovrebbero essere eseguite tramite unique_lock glock
mutex non 'raw' gmtx
. Ad esempio, alpha
la funzione membro viene riscritta con lock_guard<unique_lock<mutex>>
(o semplicemente lock_guard<decltype(glock)>
).
Potresti semplicemente usare un recursive_mutex
, che può essere bloccato più volte sullo stesso thread. Nota:se fosse il mio codice, lo ristrutturerei in modo da non aver bisogno di un recursive_mutex
, ma risolverà il tuo problema.