可能volatile是用户定义的类型,以帮助编写线程安全的代码 [英] May volatile be in user defined types to help writing thread-safe code

查看:97
本文介绍了可能volatile是用户定义的类型,以帮助编写线程安全的代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道,在之前的几个问题/答案中已经非常清楚, volatile 与c ++内存模型的可见状态相关,而不是多线程。



另一方面,此文章< a> by Alexandrescu使用 volatile 关键字不作为运行时功能,而是作为编译时检查强制编译器无法接受可能不是线程安全的代码。在文章中,关键字更像是 required_thread_safety 标签,而不是 volatile 的实际使用。



这个(ab)使用 volatile 是否合适?



注意到的第一件事情添加了混乱: volatile



本文的基本简化:



如果你声明一个变量 volatile ,只能调用 volatile 成员方法编译器将阻塞调用代码到其他方法。将 std :: vector 实例声明为 volatile 将阻止该类的所有使用。添加一个执行 const_cast 以释放 volatile 要求的锁定指针形式的包装器,任何通过

  

template< typename T>
class LockingPtr {
public:
//构造函数/析构函数
LockingPtr(volatile T& obj,Mutex& mtx)
:pObj_(const_cast< T * (& obj)),pMtx _(& mtx)
{mtx.Lock(); }
〜LockingPtr(){pMtx _-> Unlock(); }
//指针行为
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_; //控制对buffer_
}的访问;



在第一对答案出现后,我想我必须澄清,因为我可能没有使用最合适的词。



使用 volatile 不是因为它在运行时提供的,而是因为它在编译时意味着什么。也就是说,如果在用户定义的类型中很少使用 const 关键字,则可以使用 volatile 是。也就是说,有一个关键字(恰好是易变的),允许我阻止成员函数调用,而Alexandrescu使用它来欺骗编译器无法编译线程不安全的代码。



我看到很多元编程技巧,因为它们在编译时没有做什么,而是它强迫编译器为你做的。

volatile 提供的线程安全问题。 It dosen't and Andrei's article dosen't say it does。这里,使用 mutex 来实现。问题是,是否使用 volatile 关键字提供静态类型检查 以及对线程使用互斥 - 安全代码,是否滥用 volatile 关键字? IMHO很聪明,但我遇到的开发者谁不是严格类型检查的粉丝只是为了它。



IMO在为多线程环境编写代码时,已经足够小心强调,其中你希望人们不会不知道种族条件和死锁。



这种包装方法的一个缺点是,使用 LockingPtr 包装的类型上的每个操作都必须通过成员函数。



但是如果你是一个纯粹主义者,相信C ++的精神aka

em> strict-type-checking ;这是一个很好的选择。


I know, it has been made quite clear in a couple of questions/answers before, that volatile is related to the visible state of the c++ memory model and not to multithreading.

On the other hand, this article by Alexandrescu uses the volatile keyword not as a runtime feature but rather as a compile time check to force the compiler into failing to accept code that could be not thread safe. In the article the keyword is used more like a required_thread_safety tag than the actual intended use of volatile.

Is this (ab)use of volatile appropriate? What possible gotchas may be hidden in the approach?

The first thing that comes to mind is added confusion: volatile is not related to thread safety, but by lack of a better tool I could accept it.

Basic simplification of the article:

If you declare a variable volatile, only volatile member methods can be called on it, so the compiler will block calling code to other methods. Declaring an std::vector instance as volatile will block all uses of the class. Adding a wrapper in the shape of a locking pointer that performs a const_cast to release the volatile requirement, any access through the locking pointer will be allowed.

Stealing from the article:

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_
};

NOTE

After the first couple of answers have appeared I think I must clarify, as I might not have used the most appropriate words.

The use of volatile is not because of what it provides at runtime but because of what it means at compile time. That is, the same trick could be pulled with the const keyword if it was as rarely used in user defined types is as volatile is. That is, there is a keyword (that happens to be spelled volatile) that allows me to block member function calls, and Alexandrescu is using it to trick the compiler into failing to compile thread-unsafe code.

I see it as many metaprogramming tricks that are there not because of what they do at compile time, but rather for what it forces the compiler to do for you.

解决方案

I think the issue is not about thread-safety provided by volatile. It dosen't and Andrei's article dosen't say it does. Here, a mutex is used to achieve that. The issue is, whether the use of volatilekeyword to provide static type-checking along with use of mutex for thread-safe code, is abuse of the volatile keyword? IMHO it's pretty smart, but i have come across developers who are not fans of strict-type-checking just for the sake of it.

IMO when you are writing code for multi-threaded environment, there is already enough caution to emphasize wherein you would expect people not to be ignorant of race-conditions and deadlocks.

A downside of this wrapped approach is that every operation on the type that is wrapped using LockingPtr must be through a member function. That will increase one level of indirection which might considerably affect developers comfort in a team.

But if you are a purist who believes in the spirit of C++ a.k.a strict-type-checking; this is a good alternative.

这篇关于可能volatile是用户定义的类型,以帮助编写线程安全的代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆