【问题标题】:Is it wise to lock a mutex to just return a value?锁定互斥体只返回一个值是否明智?
【发布时间】:2014-08-17 18:31:52
【问题描述】:
class Foo {
public:
    // ...
    const int &getBar() const noexcept;

    void doSomethingWithBar(); // (2)

private:
    std::mutex barMutex;
    int bar = 7;
};

const int &Foo::getBar() const noexcept {
    std::lock_guard<std::mutex> lock(this->barMutex); // (1)
    return this->bar;
}

void Foo::doSomethingWithBar() {
    std::lock_guard<std::mutex> lock(this->barMutex); // necessary here
    this->bar++;
}

在线程安全方面,考虑到另一个线程可能会干扰并调用2行中的函数,从而改变bar的值,是否需要行1

请注意,int 在这里可能是任何类型。

【问题讨论】:

  • 您担心的是错误的事情。第 (1) 行既没有帮助也没有伤害,因为下一行从不读取 bar 的值。竞争条件将发生在调用代码中,它可能会通过您返回的引用读取值,没有保护。
  • @Igor 错了,第 1 行为我们提供了重要的可见性保证!
  • @Voo:它保证什么变化的可见性?
  • 此外,返回const int &amp; 几乎总是毫无意义的。
  • 如果类是完全线程安全的,那么barMutex的目的是什么?为什么要给已经在内部执行必要同步的类添加一层外部同步?

标签: c++ multithreading thread-safety mutex


【解决方案1】:

当您返回一个引用时,在这种情况下锁定对您来说完全没用。当您使用返回的引用时,您可能需要一个锁。

但是,如果您要返回一个值,它会产生更大的影响,请查看 this 以获取撕裂读取的示例。

【讨论】:

  • 只在写入时锁定互斥体,而不是在读取时锁定,将导致竞争条件,因为它允许在发生写入的同时读取。所以不,这并不能解决任何问题。
  • @IgorTandetnik 感谢您指出这一点,我把它与 std::atomic 混淆了。将编辑答案。
【解决方案2】:

第 1 行没有达到您期望的效果:显然,您尝试锁定对象并使其保持锁定状态,同时调用者处理返回的引用。

但是你创建的 lock_gard 是 getBar() 的一个本地对象,一返回就得到destroyed,从而解锁你刚刚获得的锁。

几种选择,例如:

  • 您可以更改您的函数以返回 bar 的值,但考虑到该值是一​​个快照,当您使用它时可能会过时。

  • 您还可以更改函数以一次性获取和处理 bar(例如,通过提供函数作为参数)。

  • 您还可以将锁作为类成员进行管理,并提供函数 releaseBar() 以在不再需要互斥锁时立即解锁。然而,这是一种更危险的方法,因为调用者可能会忘记释放锁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-07
    • 1970-01-01
    • 2010-12-08
    • 1970-01-01
    • 2011-04-08
    • 2023-03-15
    • 1970-01-01
    相关资源
    最近更新 更多