Я знаю, что в нескольких вопросах/ответах ранее было совершенно ясно, что volatile
связано с видимым состоянием модели памяти С++, а не с многопоточностью.
С другой стороны, в этой статье автор Александреску использует ключевое слово 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
связано не с тем, что он предоставляет во время выполнения, а с тем, что он означает во время компиляции. То есть тот же трюк можно было бы провернуть с ключевым словом const
, если бы оно так же редко использовалось в определяемых пользователем типах, как volatile
. То есть есть ключевое слово (которое пишется как volatile), которое позволяет мне блокировать вызовы функций-членов, и Александреску использует его, чтобы заставить компилятор не компилировать небезопасный для потоков код.
Я вижу в этом множество трюков метапрограммирования, которые существуют не из-за того, что они делают во время компиляции, а скорее из-за того, что это заставляет компилятор делать за вас.
volatile
и темы в одной и той же статье и прыгали на нее, даже не пытаясь понять, в чем заключается идея. - person sbi   schedule 05.04.2011