Mutex when returning an object value

If I understand how C ++ compilers handle local variables, then IsShutdownInProgress() does not need any locking, since the static variable shutdownInProgress will be IsShutdownInProgress() stack. Am I right?

 class MyClass { private: // Irrelevant code commented away static pthread_mutex_t mutex; static bool shutdownInProgress; public: static void ShutdownIsInProgress() { pthread_mutex_lock(mutex); shutdownInProgress = true; pthread_mutex_unlock(mutex); } static bool IsShutdownInProgress() { // pthread_mutex_lock(mutex); // pthread_mutex_unlock(mutex); return shutdownInProgress; } } 
+6
source share
3 answers

Am I right?

No. This will make a copy of it to return; but reading it to make this copy without synchronization will give a data race with undefined behavior. You will need to make a local copy of this file with a locked mutex:

 static bool IsShutdownInProgress() { pthread_mutex_lock(mutex); bool result = shutdownInProgress; pthread_mutex_unlock(mutex); return result; } 

or, using a less error-blocked type of blocking RAII:

 static bool IsShutdownInProgress() { lock_guard lock(mutex); return shutdownInProgress; } 

In C ++ 11, you can consider std::atomic<bool> for more convenient and possibly more efficient access to simple types from multiple threads.

+8
source

Race conditions are not related to whether the variable is on the heap or on the stack. A race condition is when one thread changes a variable (memory cell), and another thread reads or modifies the same variable. There is no guarantee that the modification of a bool is atomic, so the published code has a race state and therefore undefined behavior.

The fix will be to save the bool value when the mutex is held and returns a variable:

 static bool IsShutdownInProgress() { pthread_mutex_lock(&mutex); bool result = shutdownInProgress; pthread_mutex_unlock(&mutex); return result; } 

C ++ 11 introduced std::mutex and std::lock_guard , which can be used, and using lock_guard would avoid the requirement of a temporary variable to keep the bool value to return:

 static std::mutex mtx_; static bool IsShutdownInProgress() { std::lock_guard<std::mutex> lk(mtx_); return shutdownInProgress; } 

C ++ 11 also introduced std::atomic<> , which would ensure that the modification was atomic and avoided explicit blocking:

 static std::atomic<bool> shutdownInProgress; static bool IsShutdownInProgress() { return shutdownInProgress; } 

If C ++ 11 is not available, boost::atomic was introduced in version 1.53.0, and boost also has the equivalent of boost::mutex and boost::lock_guard .

+2
source

Yes, he needs a lock

The C ++ 11 memory model states that you have a data race if any threads write a value simultaneously with another thread reading it. This is due to the fact that reading and / or writing cannot be atomic.

In this case, you will return a local function, but to get it, the compiler must copy the value to shutdownInProgress , which can be simultaneously changed by another thread that calls ShutdownIsInProgress() .

An easy way to solve this is to make shutdownInProgress atomic:

 static std::atomic<bool> shutdownInProgress; 

If you make it atomic, you don't need any locks for any function

+1
source

Source: https://habr.com/ru/post/944881/


All Articles