繁体   English   中英

c ++ 11原子对象的执行是否也是原子的?

[英]Is the execution of a c++ 11 atomic object also atomic ?

我有一个对象,其所有功能应按顺序执行。 我知道可以使用互斥锁来做到这一点

#include <mutex> 

class myClass {
private:
    std::mutex mtx;
public:
    void exampleMethod();
};

void myClass::exampleMethod() {
    std::unique_lock<std::mutex> lck (mtx); // lock mutex until end of scope

    // do some stuff
}

但是使用此技术时,在exampleMethod中调用其他互斥锁方法后会发生死锁。

所以我正在寻找更好的分辨率。 默认的std :: atomic访问是顺序一致的,因此不可能同时读取对该对象的写入,但是现在当我访问对象并调用方法时,整个函数调用是否也是原子的或更多类似的东西

object* obj = atomicObj.load(); // read atomic
obj.doSomething(); // call method from non atomic object;

如果是,有没有比使用互斥锁锁定大多数功能更好的方法了?

停下来想一想何时实际需要锁定互斥锁。 如果您有一些在许多其他函数中调用的辅助函数,则它可能不应尝试锁定互斥锁,因为调用者已经拥有了。

如果在某些情况下没有被另一个成员函数调用,因此确实需要获取锁,请提供一个实际执行该操作的包装器函数。 具有两个版本的成员函数,公共foo()和私有fooNoLock()并不罕见,其中:

public:
void foo() {
    std::lock_guard<std::mutex> l(mtx);
    fooNoLock();
}

private:
void fooNoLock() {
    // do stuff that operates on some shared resource...
}

根据我的经验,递归互斥是一种代码味道 ,表明作者并没有真正意识到使用函数的方式-并非总是错误的,但是当我看到一个时,我就感到可疑。

至于原子运算,它们实际上只能应用于较小的算术运算,例如递增整数或交换2个指针。 这些操作不是自动的原子操作,但是当您使用原子操作时,它们是可以用于这些操作的种类。 您肯定对单个原子对象上的2个独立操作没有任何合理的期望。 在两次操作之间可能发生任何事情。

您可以改用std :: recursive_mutex 这将使已拥有的线程互斥以重新获取它而不会阻塞。 但是,如果另一个线程尝试获取该锁,它将阻塞。

正如@BoBTFish正确指出的那样,最好将您的类的公共接口分开,该成员函数获取非递归锁,然后调用那些非递归锁。 然后,您的代码必须假定在运行私有方法时始终保持锁定。

为了安全起见,您可以向每个需要保持锁的方法添加对std::unique_lock<std::mutex>的引用。

因此,即使您碰巧从另一个调用一个私有方法,也需要确保互斥体在执行之前被锁定:

class myClass
{
  std::mutex mtx;

//
  void i_exampleMethod(std::unique_lock<std::mutex> &)
  {
     // execute method
  }

public:
  void exampleMethod()
  {
    std::unique_lock<std::mutex> lock(mtx);
    i_exampleMethod(lock);
  }
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM