volatile
与C++内存模型的可见状态有关,而不是与多线程有关。另一方面,这篇由Alexandrescu撰写的article将
volatile
关键字用作编译时检查,以强制编译器拒绝接受可能不安全的代码,而不是作为运行时特性。在文章中,该关键字更像是required_thread_safety
标记,而不是volatile
的实际预期用途。这种对
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
的使用不是因为它在运行时提供了什么,而是因为它在编译时的含义。也就是说,如果用户定义的类型中像 volatile
一样很少使用 const
关键字,那么同样的技巧可以使用 const
关键字来实现。也就是说,有一个关键字(碰巧拼写为 volatile),允许我阻止成员函数调用,Alexandrescu 正在利用它来欺骗编译器,使其无法编译线程不安全的代码。
我认为这是许多元编程技巧之一,它们存在并不是因为它们在编译时做了什么,而是因为它们强制编译器为您执行某些操作。
volatile
和“线程”在同一篇文章中出现,而没有试图理解其背后的想法。 - sbi