Git Product home page Git Product logo

Comments (2)

archibate avatar archibate commented on July 21, 2024 3

一、同一个线程重复 lock 是未定义行为

lock 的文档中我们可以看到:

If lock is called by a thread that already owns the mutex, the behavior is undefined: for example, the program may deadlock.

翻译:如果一个线程已经拥有锁,那么再调用一次 lock 是未定义行为:例如,可能发生死锁。

这是很容易理解的,因为在多线程编程模型中我们知道,同一个线程连续 lock 两次会导致死锁。但是标准说了这是未定义行为,而不是明确规定会发生死锁,所以同一个调用两次 lock 可能发生死锁,也可能发生其他事情:包括但不限于抛出异常后推出,段错误,除零错误,代码的执行顺序紊乱,改变其他变量的值,甚至电脑着火,都有可能发生,当然也可能不产生任何错误,正常执行下去。

这就是未定义行为,只要你触犯了,他可以发生任何事,C++ 标准都不保护你。标准规定为未定义的,编译器都可以随便处理,发生任何事情都是你自己的责任,只不过对于 double-lock 而言大概率是“死锁”这一种情况罢了,正如空指针解引用大概率是”段错误“这一种情况一样。

之所以标准不规定是为了不要限制编译器厂商的创造力,例如官方文档后面举了个例子:“一个编译器实现可以检测到这种问题,并抛出 system_error 异常,方便用户调试。”

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.

二、同一个线程重复 try_lock 也是未定义行为

try_lock 的文档中我们还可以看到:

If try_lock is called by a thread that already owns the mutex, the behavior is undefined.

翻译:如果一个线程已经拥有锁,那么再调用一次 try_lock 也是未定义行为。

没想到8,try_lock 也不允许。

你是不是已经想当然地认为 lock 会死锁,try_lock 就不会,即使是同一个线程,也能安全返回 false?

你是不是已经想当然地认为 try_lock 的内部实现是这样的了:

bool try_lock() {
  if (!this->m_locked) {
    lock();
    return true;
  }
  return false;
}

如果标准都规定死了内部实现,不给编译器自由度,人家还怎么优化了?首先你“想当然”的这种 try_lock 内部实现就是不线程安全的。

记得我说的吗?发生未定义行为时编译器可以做任何事,包括不产生任何错误正常执行,但是打印一个错误的答案给你。

永远不要想当然,多看看 cppreference,官方文档说是未定义行为,就碰都不要去碰。不要依赖未定义行为,不要跟我说“汇编就是这样”,“我平时都是能稳定触发死锁/段错误/改变其他变量值”的。调试代码如果遇到发生任何离谱的行为时,首先检查你的代码,是不是有什么地方“想当然”了,触发未定义行为了,那发生任何事情都是合理的。

这就是 C++,听小彭老师说

所以如何修复这个未定义行为呢?标准说同一个线程多次调用 lock 或 try_lock 是未定义行为,但是他没说多个线程分别调用啊?所以你可以创建另一个线程去调用 try_lock,达到你“想当然”的那种“教学结果”。

#include <cstdio>
#include <mutex>
#include <thread>
std::mutex mtx1;
int main() {
    if (mtx1.try_lock())
        printf("succeed\n");
    else
        printf("failed\n");
    std::thread t1([] { // 同一个线程不能 double-lock,也不能 double-try_lock,但没说另一个线程不可以
        if (mtx1.try_lock())
            printf("succeed\n");
        else
            printf("failed\n");
    });
    t1.join(); // join 在 unlock 前,保证 t1 里的 try_lock 是在 main 持有锁的情况下完成执行的
    mtx1.unlock();
    return 0;
}

运行结果:

succeed
failed

from course.

YZH-bot avatar YZH-bot commented on July 21, 2024

Get,感谢指出👍

from course.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.