我知道,之前在几个问题/答案中已经很清楚了,这volatile
与 c++ 内存模型的可见状态有关,而不是与多线程有关。
另一方面,Alexandrescu 的这篇文章volatile
不是将关键字用作运行时功能,而是用作编译时检查,以强制编译器无法接受可能不是线程安全的代码。在文章中,关键字的使用更像是一个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_
};
笔记
在出现前几个答案之后,我想我必须澄清一下,因为我可能没有使用最合适的词。
的使用volatile
不是因为它在运行时提供了什么,而是因为它在编译时意味着什么。也就是说,const
如果关键字在用户定义的类型中很少使用,则可以使用相同的技巧volatile
。也就是说,有一个关键字(恰好拼写为 volatile)允许我阻止成员函数调用,而 Alexandrescu 正在使用它来欺骗编译器,使其无法编译线程不安全的代码。
我认为它存在许多元编程技巧,这些技巧不是因为它们在编译时做了什么,而是因为它迫使编译器为你做些什么。