[英]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.