Stream Security One Variable

I understand the concept of thread safety. I am looking for tips to simplify thread safety when trying to protect a single variable.

Let's say I have a variable:

double aPass; 

and I want to protect this variable, so I create a mutex:

 pthread_mutex_t aPass_lock; 

Now there are two good ways that I can come up with, but they both have unpleasant flaws. The first is to create a thread protected class to store the variable:

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

Now it will keep aPass completely safe, nothing can be wrong and ever touch it, YAY! however, look at this whole mess and imagine the confusion when accessing it. gross.

Another way is to make them available and make sure you lock the mutex before using aPass.

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

But what if someone new comes to the project, what if you forget once to block it. I do not like to debug problems with threads, they are complicated.

Is there a good way (using pthreads, because I have to use QNX, which has a little support support). To lock individual variables without a large class, and it's safer, just create a mutex lock to go with it?

+6
source share
6 answers

To raise my decision, it will be something like this.

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

In addition, to make it unique, it is best to make all statements and members static. For this you need to use iep CRTP

 template <typename ThreadSafeDataType,class DerivedDataClass> class ThreadSafeData{ //.... }; class apass:public ThreadSafeData<int,apass> 
+3
source
 std::atomic<double> aPass; 

if you have C ++ 11.

+6
source

You can easily create your own class that blocks the mutex when building and unlocks it when destroyed. This way, no matter what happens, the mutexes will be freed upon return, even if an exception is thrown or some path is executed.

 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"); } } 

The m_SharedVar variable provides a mutual exception between Function1() and Function2() and will always be unlocked upon return.

boost has built-in types to do this: boost :: scoped_locked, boost :: lock_guard.

+2
source

You can create a class that acts as a common wrapper around your variable by synchronizing access to it.

Add operator overload for assignment and you are done.

+1
source

Consider using the RAII idiom , the code below is just an idea, it has not been tested:

 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); 
+1
source

You can change your aPass class using statements instead of get / set:

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

Using:

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

Of course, it could be a template to support other types. Please note, however, that the mutex is redundant in this case. Typically, memory protection is sufficient to protect loads and storages of small data types. If possible, you should use C ++ 11 std::atomic<double> .

+1
source

All Articles