c++的单线程 mutex 问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Attenton
V2EX    C++

c++的单线程 mutex 问题

  •  
  •   Attenton 2023-08-14 19:48:40 +08:00 1912 次点击
    这是一个创建于 856 天前的主题,其中的信息可能已经有所发展或是发生改变。

    今天在学习std::recursive_mutex的时候看到std::recursive_mutex的应用场景是可重入申请锁,于是写了代码进行测试,确实在循环调用的时候不会出现死锁了。之后又用mutex进行了测试,但是发现在不同场景下会有不同的情况,代码如下:

    #include <iostream> #include <muex> 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 。

    12 条回复    2023-08-15 16:26:21 +08:00
    Attenton
        1
    Attenton  
    OP
       2023-08-14 19:51:01 +08:00
    补充:CmakeLists.txt 里面没有添加任何编译选项,cmake 版本是 3.18 , 用的 c++ 17
    iwdmb
        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
    Attenton
        3
    Attenton  
    OP
       2023-08-14 19:58:32 +08:00
    @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.

    以上是我的执行结果,没搞懂是哪的问题
    Attenton
        4
    Attenton  
    OP
       2023-08-14 20:07:09 +08:00
    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/
    ysc3839
        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
    所以按照预期,以上代码发生什么事都有可能
    Attenton
        6
    Attenton  
    OP
       2023-08-14 20:09:54 +08:00
    @ysc3839 嗯嗯,我也找到了,感谢
    geelaw
        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 是一样的效果,是符合标准的。
    Attenton
        8
    Attenton  
    OP
       2023-08-14 20:15:37 +08:00
    @geelaw 感谢,这个标准的定义可以在哪看?
    geelaw
        10
    geelaw  
       2023-08-14 20:25:37 +08:00
    Attenton
        11
    Attenton  
    OP
       2023-08-14 20:41:04 +08:00
    @geelaw 感谢
    maplememory
        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;
    }
    ```
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5245 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 31ms UTC 05:55 PVG 13:55 LAX 21:55 JFK 00:55
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86