繁体   English   中英

线程安全单个变量

[英]Thread Safety Of a single variable

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

说我有一个变量:

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,它几乎没有提升支持)要锁定单个变量而不需要大类,那么只需创建一个互斥锁就可以更安全吗?

std::atomic<double> aPass;

只要你有C ++ 11。

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

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>

您可以轻松地创建自己的类来锁定构造上的互斥锁,并在销毁时将其解锁。 这样,无论发生什么,即使抛出异常,或者采取任何路径,都会在返回时释放互斥锁。

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。

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

为作业添加运算符重载,您就完成了。

考虑使用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);

您可以使用运算符而不是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>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM