厳密には std::mutex
のロック状態の確認についての質問でした 直接。ただし、新しいクラスにカプセル化することが許可されている場合は、非常に簡単にカプセル化できます:
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
};
以下の点に注意してください:
<オール>std::mutex
よりもオーバーヘッドがゼロです ただし、構築/破棄の場合は除きます (これはミューテックス オブジェクトでは問題になりません)。m_holder
member は、ミューテックスを取得してから解放するまでの間にのみアクセスされます。したがって、ミューテックス自体が m_holder
のミューテックスとして機能します。 .タイプ std::thread::id
に関する非常に弱い仮定 、 locked_by_caller
正常に動作します。std::lock_guard
など) はテンプレートであるため、この新しいクラスでうまく機能します。
std::unique_lock<L>
owns_lock
を持っています メンバー関数 (is_locked
と同等) あなたが言うように)。
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
}
編集: このソリューションでは、すべてのロック操作は unique_lock glock
を介して実行する必要があります 'raw' ミューテックス gmtx
ではありません .例:alpha
メンバー関数は lock_guard<unique_lock<mutex>>
で書き換えられます (または単に lock_guard<decltype(glock)>
).
recursive_mutex
を使用できます 、同じスレッドで複数回ロックできます。注:それが私のコードであれば、recursive_mutex
が不要になるように再構築します 、しかしそれはあなたの問題に対処します.