2012-11-09 79 views
6

我理解线程安全的概念。我正在寻求建议,以在尝试保护单个变量时简化线程安全性。线程安全性单个变量

说我有一个变量:

double aPass; 

,我要保护这个变量,所以我创建一个互斥体:

pthread_mutex_t aPass_lock; 

现在有两个很好的方法我能想到这样做的但他们都有恼人的缺点。首先是让一个线程安全类来保存变量:

class aPass { 
    public: 
     aPass() { 
      pthread_mutex_init(&aPass_lock, NULL); 
      aPass_ = 0; 
     } 

     void get(double & setMe) { 
      pthread_mutex_lock(aPass_lock); 
      setMe = aPass_ 
      pthread_mutex_unlock(aPass_lock); 
     } 

     void set(const double setThis) { 
      pthread_mutex_lock(aPass_lock); 
      aPass_ = setThis; 
      pthread_mutex_unlock(aPass_lock); 
     } 
    private: 
     double aPass_; 
     pthread_mutex_t aPass_lock; 
}; 

现在,这将让aPass完全安全的,没有什么可以被误认为和不断抚摸它,耶!然而,看看所有这些乱七八糟的东西,并想象它在访问时会感到困惑。毛。

另一种方法是让它们都可访问,并确保在使用aPass之前锁定互斥锁。

pthread_mutex_lock(aPass_lock); 
    do something with aPass 
pthread_mutex_unlock(aPass_lock); 

但是,如果某个新项目出现在项目中,如果您忘记一次锁定它会怎么样。我不喜欢调试线程问题,他们很难。

是否有一个很好的方法(使用pthreads,因为我必须使用QNX,它具有很小的增强支持)要锁定单个变量而不需要一个大的类,并且更安全,那么只需创建一个互斥锁就可以使用它?

+0

这个变量是一个全局变量吗?我不认为你有更多的选择..除非你想做一个通用线程安全的容器类 - 这将为你节省一些代码,如果你必须这样做第二个变种。 –

+0

你的意思是像一个模板班?听起来很不错。 –

+0

另外,是不是有可能通过你的设计来复制var? apass是一个班级,所以我可以拥有尽可能多的对象,但我想要的是 –

回答

3

为了说明我的解决方案,它会是这样的。

template <typename ThreadSafeDataType> 
class ThreadSafeData{ 
    //.... 
private: 
    ThreadSafeDataType data; 
    mutex mut; 
}; 

class apass:public ThreadSafeData<int> 

此外,为了使它与众不同,最好让所有操作员和成员都是静态的。对于这个工作,你需要使用CRTP

template <typename ThreadSafeDataType,class DerivedDataClass> 
class ThreadSafeData{ 
//.... 
}; 
class apass:public ThreadSafeData<int,apass> 
+1

欢迎来到SO!请不要在你的交流中使用txt-speak,在这里没有必要,而且通常都会被折磨。 – GManNickG

1

您可以创建一个类,作为围绕变量同步访问的变量的通用包装。

为赋值添加运算符重载并完成。

+0

一些示例代码?你的意思是每个变量类型我打算在一个类中使用,每个函数都为该类型重载。这听起来很麻烦。 –

+0

您可以创建一个可以处理任何数据类型的模板类。 – thedayofcondor

+0

请参阅@Karthik T代码...我的C++有点生疏,无法在没有IDE的情况下写下我的头顶...我太老了 – thedayofcondor

1

考虑使用RAII idiom,下面的代码只是一个想法,这不是测试:

template<typename T, typename U> 
struct APassHelper : boost::noncoypable 
{ 
    APassHelper(T&v) : v_(v) { 
    pthread_mutex_lock(mutex_); 
    } 
    ~APassHelper() { 
    pthread_mutex_unlock(mutex_); 
    } 
    UpdateAPass(T t){ 
    v_ = t; 
    } 
private: 
    T& v_; 
    U& mutex_; 
}; 

double aPass; 
int baPass_lock; 
APassHelper<aPass,aPass_lock) temp; 
temp.UpdateAPass(10); 
+0

这仍然需要用户手动使用助手,OP想要避免 –

2

您可以轻松地制作自己的类,锁定互斥建筑,并在销毁时解锁。这样,无论发生什么情况,即使发生异常,或者执行任何路径,互斥锁都将被释放。

class MutexGuard 
{ 
    MutexType & m_Mutex; 
public: 

    inline MutexGuard(MutexType & mutex) 
     : m_Mutex(mutex) 
    { 
     m_Mutex.lock(); 
    }; 

    inline ~MutexGuard() 
    { 
     m_Mutex.unlock(); 
    }; 
} 


class TestClass 
{ 
    MutexType m_Mutex; 
    double m_SharedVar; 

    public: 
     TestClass() 
      : m_SharedVar(4.0) 
     { } 

     static void Function1() 
     { 
      MutexGuard scopedLock(m_Mutex); //lock the mutex 
      m_SharedVar+= 2345; 
      //mutex automatically unlocked 
     } 
     static void Function2() 
     { 
      MutexGuard scopedLock(m_Mutex); //lock the mutex 
      m_SharedVar*= 234; 
      throw std::runtime_error("Mutex automatically unlocked"); 
     } 

} 

变量m_SharedVar确保互斥Function1()Function2()之间,并且将始终在返回解锁。

boost有构建类型来完成这个:boost :: scoped_locked,boost :: lock_guard。

+1

很酷的答案,但不幸的是我说我的问题我不能使用提升。否则,我会遍布有限范围的互斥锁。 –

+3

他已经告诉你如何使你自己的有限锁 –

1

您可以通过使用运营商,而不是对get/set修改aPass类:

class aPass { 
public: 
    aPass() { 
     pthread_mutex_init(&aPass_lock, NULL); 
     aPass_ = 0; 
    } 

    operator double() const { 
     double setMe; 
     pthread_mutex_lock(aPass_lock); 
     setMe = aPass_; 
     pthread_mutex_unlock(aPass_lock); 
     return setMe; 
    } 

    aPass& operator = (double setThis) { 
     pthread_mutex_lock(aPass_lock); 
     aPass_ = setThis; 
     pthread_mutex_unlock(aPass_lock); 
     return *this; 
    } 
private: 
    double aPass_; 
    pthread_mutex_t aPass_lock; 
}; 

用法:

aPass a; 
a = 0.5; 
double b = a; 

这当然可以作为模板来支持其他类型。但请注意,在这种情况下,互斥体是矫枉过正的。通常,在保护小数据类型的加载和存储时,内存屏障就足够了。如果可能的话,你应该使用C++ 11 std::atomic<double>

5
std::atomic<double> aPass; 

只要你有C++ 11。

+0

不幸的是,我没有c + + 11 –