In the world of concurrency, sometimes what traps you is not others, but yourself.
<span>recursive_mutex</span>
<span>mutex</span>is the most basic and commonly used magic door. Regarding this category, C++ provides us with more options. Today, let’s take a look at<span>recursive_mutex</span>!
1. The Illusion of Deadlock 🪤
Imagine a task that rewards you with 100W💰 upon completion, with the following rules:
- You🔓 open the magic door (
<span>mutex</span>)🚪 lock it (<span>lock</span>)🔒 and enter the room; - Inside the room, there is another door🚪 (
<span>mutex</span>), you continue to open it and coming out counts as completing the task. - After completing the task, unlock (
<span>unlock()</span>) to exit, and you will receive 100W 💰; - Note⚠️: When the door is closed, no one else can enter..
Sounds easy, right?! We eagerly accepted this task, entered the first door, and now we need to open the inner door~ Wait a minute……. why does this inner door look exactly like the first one..😨
You try to open the door again (🔓<span>lock</span>) — only to find that it won’t open. You are locked in your own room🏠. The door won’t let you through… because it thinks “someone is already inside,” so it refuses to open again. You are trapped in a “self-locking” Möbius strip.
std::mutex mtx;
void WorkThread(int counter){
mtx.lock();
// Recursive call, permanently locked🔒
WorkThread(--counter);
mtx.unLock();
}
2. 🧩 The Solution:<span>recursive_mutex</span>
Thus, someone invented the recursive lock (<span>recursive_mutex</span>).
It cleverly remembers who its owner is —
If the same person tries to open the door again, it will say: “Ah, it’s you, my owner! Come in.”
It also keeps track of the number of nested locks (<span>lock count</span>)🧮. It gradually “cleans up” the memories of each time you enter🔓, only when it completely forgets you~ will it allow others to become its owner (as a principled M, it will only accept a new owner after completely forgetting the previous one!)
std::recursive_mutex mtx;
void WorkThread(int counter) {
mtx.lock(); // Lock for the first time
if (counter > 0)
WorkThread(--counter); // Recursive call: lock again (allowed)
mtx.unlock(); // Unlock layer by layer
}
3. The Gatekeepers of <span>recursive_mutex</span>
Well, it’s still the same two classmates:
- Regular gatekeeper
<span>lock_guard</span>Mr. Chang - Flexible gatekeeper
<span>unique_lock</span>Mr. Ling
🔔 When inviting these two bodyguards, remember to note that you are using the recursive lock <span>recursive_mutex</span>
// Tell him who you are~
std::lock_guard<std::recursive_mutex> guard(mtx);
std::unique_lock<std::recursive_mutex> lock(mtx, std::defer_lock)
Lest You Forget
<span>recursive_mutex</span> allows us to avoid the embarrassment of “locking ourselves” in recursive calls and member function calls.
But remember👇
| ⚙️ Features | Description |
|---|---|
| ✅ Supports repeated locking by the same thread | The same thread can lock multiple times <span>lock</span> |
| ⚠️ Must match unlock counts | <span>unlock</span> count must equal <span>lock</span> count |
🐢 Performance slightly slower than <span>mutex</span> |
Because it needs to maintain the count |
| 💡 Use cases | When recursive functions or member functions need to be locked |
| 🚫 Not recommended for abuse | If recursion locks can be avoided by refactoring logic, they should be avoided first |