今天在学习std::recursive_mutex
的时候看到std::recursive_mutex
的应用场景是可重入申请锁,于是写了代码进行测试,确实在循环调用的时候不会出现死锁了。之后又用mutex
进行了测试,但是发现在不同场景下会有不同的情况,代码如下:
#include <iostream>
#include <mutex>
std::recursive_mutex recursive_mutex_;
std::mutex mutex_;
void func(int n) {
std::lock_guard<std::mutex> lock(mutex_);
std::cout << "n = " << n << std::endl;
if (n > 0) {
func(n - 1);
}
}
int main() {
func(5);
return 0;
}
按照预期,以上代码应该在打印了 5 之后就一直卡主,可是在 gcc 7.5 下,直接打印了 5 4 3 2 1 ;测试了很多在线编译器都是这个现象,只有https://www.onlinegdb.com/online_c++_compiler 这个在线编译器的运行结果符合预期。
请问各位大佬,这个现象的原因是什么? 应该不是 lock_guard 的问题,因为我自己手写了 lock_guard 查看了 lock 的声明周期,确实是在 func 执行结束之后才 unlock 。
1
Attenton OP 补充:CmakeLists.txt 里面没有添加任何编译选项,cmake 版本是 3.18 , 用的 c++ 17
|
2
iwdmb 2023-08-14 19:52:07 +08:00
~/Project/C/testtest$ g++ --version
g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 Copyright (C) 2021 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ~/Project/C/testtest$ ./a.out n = 5 |
3
Attenton OP @iwdmb
(base) root@ubuntu:/home# ./a.out n = 5 n = 4 n = 3 n = 2 n = 1 n = 0 (base) root@ubuntu:/home# g++ --version g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 Copyright (C) 2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 以上是我的执行结果,没搞懂是哪的问题 |
4
Attenton OP If lock is called by a thread that already owns the mutex, the behavior is undefined: for example, the program may deadlock. An implementation that can detect the invalid usage is encouraged to throw a std::system_error with error condition resource_deadlock_would_occur instead of deadlocking.
If the mutex is currently locked by the same thread calling this function, it produces a deadlock (with undefined behavior). 是个 undefined behavior ,不能这样使用,结贴😓 Reference: https://en.cppreference.com/w/cpp/thread/mutex/lock https://cplusplus.com/reference/mutex/mutex/lock/ |
5
ysc3839 2023-08-14 20:07:33 +08:00 via Android 1
https://en.cppreference.com/w/cpp/thread/mutex/lock
If lock is called by a thread that already owns the mutex, the behavior is undefined 所以按照预期,以上代码发生什么事都有可能 |
7
geelaw 2023-08-14 20:11:22 +08:00 1
n4849 § 32.5.3.2 没有定义 std::mutex 重入的情况,并且 § 32.5.3.2.1 提示
A program can deadlock if the thread that owns a mutex object calls lock() on that object. If the implementation can detect the deadlock, a resource_deadlock_would_occur error condition might be observed. 没有说必须死锁或者抛出异常。令 std::mutex 和 std::recursive_mutex 是一样的效果,是符合标准的。 |
9
geelaw 2023-08-14 20:24:55 +08:00 1
|
10
geelaw 2023-08-14 20:25:37 +08:00
|
12
maplememory 2023-08-15 16:26:21 +08:00
虽说是 UB ,但通常应该是死锁才对。我估计是单线程没有竞态的原因。这样写就卡在 5 了
```c++ #include <iostream> #include <mutex> #include <thread> std::mutex mtx; int n = 5; void func() { std::lock_guard<decltype(mtx)> lock(mtx); std::cout << "n = " << n-- << std::end; if (n > 0) { func(); } } int main() { std::thread t([]{func();}); func(); t.join(); return 0; } ``` |