std::recursive_mutex用于解决同一线程重入加锁问题,通过计数器允许重复lock/unlock,仅计数归零才释放锁;但性能开销大、易掩盖设计缺陷、调试困难且不适用于跨线程场景。
当一个函数在持有锁的情况下又调用自身(递归),或调用另一个也尝试获取同一把锁的函数时,普通 std::mutex 会直接导致死锁——因为线程已持锁,再次 lock() 就会永远阻塞。而 std::recursive_mutex 允许同一线程反复 lock(),内部通过计数器跟踪加锁次数,只有对应次数的 unlock() 才真正释放锁。
二者接口几乎一致,但语义完全不同:
std::mutex:非递归,同一线程重复 lock() → 未定义行为(通常是死锁)std::recursive_mutex:递归安全,lock() 增计数,unlock() 减计数,仅当计数归零才释放所有权CRITICAL_SECTION)std::unique_lock / std::shared_lock 混用「自动析构释放」逻辑来简化嵌套?可以,但要注意:每次 lock() 都必须配对 unlock(),否则计数不归零,其他线程永远拿不到锁实际中多数同步需求并不需要递归。滥用 std::recursive_mutex 往往掩盖设计缺陷:
unlock() 缺失点很远std::recursive_mutex 不再提供保护(它只认“同一线程”,不认“同逻辑”)#include#include #include std::recursive_mutex rmtx; int value = 0;
void recursive_inc(int n) { rmtx.lock(); // 第一次成功;后续调用也成功 if (n > 0) { ++value; recursive_inc(n - 1); // 同一线程再次 lock() } rmtx.unlock(); // 对应本次 lock() }
int main() { std::thread t(recursive_inc, 3); t.join(); std::cout << "value = " << value << "\n"; // 输出 4 }
换成 std::mutex,这段代码在大多数实现上会卡死在第二次 。
递归锁不是银弹——它解决的是特定重入场景,但会让锁的生命周期变得隐式且难追踪。真要用,务必确保每次 lock() 都有明确对应的 unlock(),并且优先考虑是否能用更清晰的同步结构替代。