How to assert if a std::mutex is locked?
Solution 1
std::unique_lock<L>
has owns_lock
member function (equivalent of is_locked
as you say).
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
}
EDIT: In this solution, all lock operations should be performed via unique_lock glock
not 'raw' mutex gmtx
. For example, alpha
member function is rewritten with lock_guard<unique_lock<mutex>>
(or simply lock_guard<decltype(glock)>
).
Solution 2
Strictly speaking, the question was about checking the lockedness of std::mutex
directly. However, if encapsulating it in a new class is allowed, it's very easy to do so:
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
};
Note the following:
- In release mode, this has zero overhead over
std::mutex
except possibly for construction/destruction (which is a non-issue for mutex objects). - The
m_holder
member is only accessed between taking the mutex and releasing it. Thus the mutex itself serves as the mutex ofm_holder
. With very weak assumptions on the typestd::thread::id
,locked_by_caller
will work correctly. - Other STL components, e.g.,
std::lock_guard
are templates, so they work well with this new class.
Solution 3
You could just use a recursive_mutex
, which can be locked multiple times on the same thread. Note: If it were my code, I would restructure it so that I don't need a recursive_mutex
, but it will address your problem.
Solution 4
Try atomic (e.g. atomic<bool>
or atomic<int>
), which has a nice load function that will do what you want, as well as other nice functions like compare_exchange_strong.
Solution 5
Well, if the expense of the assertion really isn't an issue then you can just call try_lock()
from another thread where its behavior is guaranteed to be well defined:
void beta(void) {
assert(std::async(std::launch::async, [] { return gmtx.try_lock(); })
.get() == false &&
"error, beta called without locking gmtx");
// some real work
}
Basile Starynkevitch
My resume is downloadable here. See my web page on http://starynkevitch.net/Basile/ ; most of the time I am typing from my home at Bourg-La-Reine. You can email me to [email protected] My pet -hobby- open source project (in artificial intelligence, for Linux) is RefPerSys (still unfunded in end of 2021, and done with others). I dream to have more time to devote to it. You'll make me happy by compiling it on your Linux box, and give feedback; Contact me for potential applications or funding opportunities. I am an enthusiast of free software, and know quite well Linux (which I am using since 1994) I think that high-level languages are important, and that declarative knowledge-based systems should be more used (see J.Pitrat's blog ...) You might contact me by an email to basile at starynkevitch dot net but please give the URL of your question in your message. I am French,I am a man (born in 1959), a husband, a grand father, and have a PhD in CS (artificial intelligence, 1990, Paris LIP6) and graduated from ENS Cachan. My native tongue is French. My parents spoke Russian to me. In Russian my full name is Василий Дмитриевич Старынкевич ; in English my first (christian) name is spelled Basil. If you send me an email to [email protected] use French, or English, or Russian and mention the URL of your question. My Russian spelling is so bad that I dare not use it in emails (so I would answer in English to any Russian email). See https://github.com/bstarynk/ and and https://gitlab.com/bstarynk/ PS. I intend to continue working on persistent reflexive systems during retirement, e.g. in http://refpersys.org/ .... I find H2020 projects excessively bureaucratic: its paperwork is really overwheling. My email is public: [email protected] and I don't use social media. Photo done by my son Matthieu Starynkevitch (oct. 2019)
Updated on December 02, 2020Comments
-
Basile Starynkevitch over 3 years
With GCC 4.8.2 (on Linux/Debian/Sid 64 bits) -or GCC 4.9 when available - in C++11- I have some mutex
std::mutex gmtx;
actually, it is a
static
member in some classFoo
containing bothalpha
andbeta
methods below.it is locked in
alpha
likevoid alpha(void) { std::lock_guard<std::mutex> g(gmtx); beta(void); // some other work }
and I want to check in
beta
that indeedgmtx
is locked:void beta(void) { assert (gmtx.is_locked()); // some real work }
(notice that
is_locked
is only called insideassert
... It can be very inefficient or even sometimes inaccurate)Of course, I have other functions calling
beta
, e.g.void gamma(void) { std::lock_guard<std::mutex> g(gmtx); beta(); // some other work }
but
is_locked
does not exist.... How should I define it? (actually I would like to be sure that the mutex has been locked in the same thread by some [indirect] caller...)(the reason I want to test that with
assert
is thatbeta
could be called elsewhere)I cannot use
try_lock
(unless using recursive mutexes), because in the common case it would lock an already locked mutex... (locked in the same thread by a caller) and this is not only undefined behavior but blocks entirely.I want to avoid recursive mutexes (more costly than plain mutexes) unless I really have to.
NB: The real program is a bit more complex. Actually, all the methods are inside a class which maintain a naming bi-directional relation on "items". So I have inside that class a map from items to names and another from names to items.
beta
would be the internal method adding really a naming, andalpha
andgamma
would be the methods finding -or adding- an item by its name, or a name by its item.PS: the real program is not yet released, but should become part of MELT - its future monitor; you can download it (alpha stage, very buggy) from here (a temporary location)