Dav*_*eas 25 c++ volatile thread-safety
我知道,之前的几个问题/答案已经很明确了,这volatile与c ++内存模型的可见状态有关,而与多线程无关.
另一方面,Alexandrescu的这篇文章使用volatile关键字not作为运行时特性,而是使用编译时检查来强制编译器无法接受可能不是线程安全的代码.在文章中,关键字的使用更像是required_thread_safety标签,而不是实际的预期用途volatile.
这(ab)使用volatile合适吗?方法中可能隐藏了哪些可能的陷阱?
首先想到的是增加了混乱:volatile与线程安全无关,但由于缺乏更好的工具,我可以接受它.
文章的基本简化:
如果声明一个变量volatile,则只能volatile在其上调用成员方法,因此编译器将阻止调用其他方法的代码.声明std::vector实例volatile将阻止该类的所有使用.添加一个执行const_cast释放volatile需求的锁定指针形状的包装器,将允许通过锁定指针进行任何访问.
窃取文章:
template <typename T>
class LockingPtr {
public:
// Constructors/destructors
LockingPtr(volatile T& obj, Mutex& mtx)
: pObj_(const_cast<T*>(&obj)), pMtx_(&mtx)
{ mtx.Lock(); }
~LockingPtr() { pMtx_->Unlock(); }
// Pointer behavior
T& operator*() { return *pObj_; }
T* operator->() { return pObj_; }
private:
T* pObj_;
Mutex* pMtx_;
LockingPtr(const LockingPtr&);
LockingPtr& operator=(const LockingPtr&);
};
class SyncBuf {
public:
void Thread1() {
LockingPtr<BufT> lpBuf(buffer_, mtx_);
BufT::iterator i = lpBuf->begin();
for (; i != lpBuf->end(); ++i) {
// ... use *i ...
}
}
void Thread2();
private:
typedef vector<char> BufT;
volatile BufT buffer_;
Mutex mtx_; // controls access to buffer_
};
Run Code Online (Sandbox Code Playgroud)
注意
在出现前几个答案之后,我想我必须澄清一下,因为我可能没有使用最合适的词.
使用volatile它不是因为它在运行时提供的内容,而是因为它在编译时的含义.也就是说,const如果在用户定义类型中很少使用关键字,则可以使用关键字拉出相同的技巧volatile.也就是说,有一个关键字(恰好是拼写易失性)允许我阻止成员函数调用,而Alexandrescu正在使用它来欺骗编译器无法编译线程不安全的代码.
我认为很多元编程技巧不是因为它们在编译时所做的,而是因为它迫使编译器为你做的事情.
我认为问题不在于提供的线程安全性volatile.它没有,安德烈的文章也没有说它确实如此.这里,a mutex用于实现这一点.问题是,是否使用volatile关键字来提供静态类型检查以及使用互斥锁进行线程安全代码是滥用volatile关键字?恕我直言,它非常聪明,但我遇到的开发人员不仅仅是为了它而不是严格类型检查的粉丝.
IMO在为多线程环境编写代码时,已经有足够的谨慎强调,你会期望人们不要不了解竞争条件和死锁.
这种包装方法的缺点是,使用包装的类型的每个操作都LockingPtr必须通过成员函数.这将增加一个间接水平,这可能会显着影响开发人员在团队中的舒适度.
但如果你是一个纯粹的人,他相信C++的精神,即严格的类型检查 ; 这是一个很好的选择.