If I understand how C++ compilers handle local variables then IsShutdownInProgress() does not need any locking since the shutdownInProgress static variable will be placed on the stack. Am I correct?
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;
}
}
Am I correct?
No. This will make a copy of it to return; but reading it to make that copy without synchronisation will give a data race, with undefined behaviour. You'll need to make a local copy of it with the mutex locked:
static bool IsShutdownInProgress()
{
pthread_mutex_lock(mutex);
bool result = shutdownInProgress;
pthread_mutex_unlock(mutex);
return result;
}
or, using a less error-prone RAII lock type:
static bool IsShutdownInProgress()
{
lock_guard lock(mutex);
return shutdownInProgress;
}
In C++11, you might consider std::atomic<bool> for more convenient, and perhaps more efficient, access to simple types from multiple threads.
Race conditions are unrelated to whether a variable is located on the heap or on the stack. A race condition is when one thread is modifying a variable (a memory location) and another thread is reading or modifying the same variable. There is no guarantee that the modification of a bool is atomic so the posted code has a race condition, and therefore undefined behaviour.
A fix would be to store the value of the bool when the mutex is held and return the 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 that could be used and the use of the lock_guard would avoid the requirement of a temporary variable to store the bool value for return:
static std::mutex mtx_;
static bool IsShutdownInProgress()
{
std::lock_guard<std::mutex> lk(mtx_);
return shutdownInProgress;
}
c++11 also introduced std::atomic<> that would ensure the modification is atomic and avoid the need for an explicit lock:
static std::atomic<bool> shutdownInProgress;
static bool IsShutdownInProgress()
{
return shutdownInProgress;
}
If c++11 is unavailable to boost::atomic was introduced in v1.53.0 and boost also has equivalent boost::mutex and boost::lock_guard.
Yes, it needs a lock
C++11's memory model states you have a data race if any threads are writing a value at the same time as another thread reading it. This is because both a read and/or a write may not be atomic.
In this case you will return a local from the function, but to get that local the compiler needs to copy the value in shutdownInProgress, which may be concurrently being changed by another thread calling ShutdownIsInProgress().
An easy way to solve this is to make shutdownInProgress an atomic:
static std::atomic<bool> shutdownInProgress;
If you make it atomic, you don't need any locks at all for either function
Related
int data {}
atomic<bool> syncer {false};
void foo()
{
syncer = true; //---> I could have used a mutex here and writelock
data = 5;
syncer = false;
}
void foo2()
{
if (syncer) // If I used a mutex I could have read lock here
return 0;
return data;
}
I always use atomics instead of mutexes. But today in a code review, I was told to use mutexes. Then I explained that atomics may not lock and this is an advantage over mutexes.
So, both my reviewer and I ended up with a question: What is the use of mutexes? Should we ban mutexes in our code guidelines and use atomics all the time? Is there a advantage of mutexes over atomics?
Let's say I have something like this:
bool signalled = false;
std::condition_variable cv;
void thread1() {
while (true) {
std::unique_lock l(mutex);
cv.wait_until(l, [] { return signalled; });
return;
}
}
void thread2...N() {
signalled = true;
cv.notify_all();
}
Is that considered thread-safe? The boolean may be set to true in many threads to interrupt thread1.
Edit: If not thread-safe I’m looking for a description of what the race condition is so I can better understand the underlying issue and fill in a knowledge gap.
Writing to a non-atomic variable without synchronization is UB. However, making signalled an atomic<bool> will not solve the problem.
C++ reference on std::condition_variable reads:
Even if the shared variable is atomic, it must be modified under the mutex in order to correctly publish the modification to the waiting thread.
You should do this:
bool signalled = false;
void thread2...N()
{
std::unique_lock l(mutex);
signalled = true;
cv.notify_all();
}
Related questions:
Mutex protecting std::condition_variable
Shared atomic variable is not properly published if it is not modified under mutex
Why do I need to acquire a lock to modify a shared "atomic" variable before notifying condition_variable
My Problem is that I dont know how to properly use the mutex. I understand how it works theoretically but I don´t know why it doesnt work in my code.I thought if I use a mutex on a var it will be blocked until it gets unlocked. Nevertheless it seems I still have a data race.
I tried to define a class mutex and a mutex in the main which I pass by reference. Somehow nothing of this works.
class test {
public:
void dosmth(std::mutex &a);
int getT(){return t;};
private:
int t = 0;
};
void test::dosmth(std::mutex &a) {
for(;;){
a.lock();
t++;
if(t==1000){
t=0;
}
a.unlock();
}
}
int main() {
test te;
std::mutex help;
std::thread t(&test::dosmth, std::addressof(te), std::ref(help));
for(;;){
for (int i = 0; i <te.getT() ; ++i) {
std::cout<<te.getT()<<std::endl;
}
}
}
The result just should be that I get some output so I will now it works.
As Michael mentioned, you should synchronise the reader and writer to avoid undefined behaviour. Instead of passing the mutex as an argument, a common pattern is to make the mutex a member of the object (te), lock and unlock every time (prefer lock_gaurd instead of manually locking and unlocking) you enter a member function (that modifies internal state of the object). Here is some pseudo-code:
class Foo{
std::mutex m; // reader and writer are sync'ed on the same mutex
int data_to_sync;
public:
int read(){
lock_gaurd<mutex> lg(m); //RAII lock
return data_to_sync;
//automagically released upon exit
}
void write(){
lock_gaurd<mutex> lg(m);
data_to_sync++;
}
};
A mutex can only guarantee mutual exclusion if said mutex is used to regulate entry to all critical sections of code where a given object would be accessed concurrently. In your case, you have your second thread modify the value of the object te.t while your main thread is reading the value of the same object. Only one thread, however, is using a mutex to protect the access to te.t. The object te.t is not atomic. Therefore, you have a data race and, thus, undefined behavior [intro.races]/21.
You have to also lock and unlock the mutex in your for(;;) loop in main, e.g.:
for(;;){
help.lock();
for (int i = 0; i <te.getT() ; ++i) {
std::cout<<te.getT()<<std::endl;
}
help.unlock();
}
or better, using std::lock_guard:
for(;;){
std::lock_guard lock(help);
for (int i = 0; i <te.getT() ; ++i) {
std::cout<<te.getT()<<std::endl;
}
}
I thought if I use a mutex on a var...
You don't use a mutex "on a var." Locking a mutex prevents other threads from locking the same mutex at the same time, but it does not stop other threads from accessing any particular variable(s).
If you want to use a mutex to protect a variable (or more typically, several variables) from being accessed by more than one thread at the same time, then it's up to you to ensure that you do not write any code that accesses the variables without locking the mutex first.
I am dealing with the multi-threading project with C++ and I doubt about std::mutex
Let's assume that I have a stack.
#include <exception>
#include <memory>
#include <mutex>
#include <stack>
struct empty_stack: std::exception
{
const char* what() const throw();
};
template<typename T>
class threadsafe_stack
{
private:
std::stack<T> data;
mutable std::mutex m;
public:
threadsafe_stack(){}
threadsafe_stack(const threadsafe_stack& other)
{
std::lock_guard<std::mutex> lock(other.m);
data=other.data;
}
threadsafe_stack& operator=(const threadsafe_stack&) = delete;
void push(T new_value)
{
std::lock_guard<std::mutex> lock(m);
data.push(new_value);
}
std::shared_ptr<T> pop()
{
std::lock_guard<std::mutex> lock(m);
if(data.empty()) throw empty_stack();
std::shared_ptr<T> const res(std::make_shared<T>(data.top()));
data.pop();
return res;
}
void pop(T& value)
{
std::lock_guard<std::mutex> lock(m);
if(data.empty()) throw empty_stack();
value=data.top();
data.pop();
}
bool empty() const
{
std::lock_guard<std::mutex> lock(m);
return data.empty();
}
};
Someone said that using this stack can avoid race condition. However I think that problem here is that mutex aka mutual exclusion here only ensure for individual function not together. For example, I can have the threads call push and pop. Those function still have problem of race condition.
For example:
threadsafe_stack st; //global varibale for simple
void fun1(threadsafe_stack st)
{
std::lock_guard<std::mutex> lock(m);
st.push(t);
t = st.pop();
//
}
void fun2(threadsafe_stack st)
{
std::lock_guard<std::mutex> lock(m);
T t,t2;
t = st.pop();
// Do big things
st.push(t2);
//
}
If a thread fun1 and fun2 call the same stack (global variable for simple). So it can be a race condition(?)
I have only solution I can think is using some kind of atomic transaction means instead of calling directly push(), pop(), empty(), I call them via a function with a "function pointer" to those function and with only one mutex.
For example:
#define PUSH 0
#define POP 1
#define EMPTY 2
changeStack(int kindOfFunction, T* input, bool* isEmpty)
{
std::lock_guard<std::mutex> lock(m);
switch(kindOfFunction){
case PUSH:
push(input);
break;
case POP:
input = pop();
break;
case EMPTY:
isEmpty = empty();
break;
}
}
Is my solution good? Or I just overthinking and the first solution my friend told me is good enough? Are there any other solution for this? The solution can avoid "atomic transaction" like I suggest.
A given mutex is a single lock and can be held by a single thread at any one time.
If a thread (T1) is holding the lock on a given object in push() another thread (T2) cannot acquire it in pop() and will be blocked until T1 releases it. At that point of release T2 (or another thread also blocked by the same mutex) will be unblocked and allowed to proceed.
You do not need to do all the locking and unlocking in one member.
The point where you may still be introducing a race condition is constructs like this if they appear in consumer code:
if(!stack.empty()){
auto item=stack.pop();//Guaranteed?
}
If another thread T2 enters pop() after thread T1 enters empty() (above) and gets blocked waiting on the mutex then the pop() in T1 may fail because T2 'got there first'. Any number of actions might take place between the end of empty() and the start of pop() in that snippet unless other synchronization is handling it.
In this case you should imagine T1 & T2 literally racing to pop() though of course they may be racing to different members and still invalidate each other...
If you want to build code like that you usually have to then add further atomic member functions like try_pop() which returns (say) an empty std::shared_ptr<> if the stack is empty.
I hope this sentence isn't confusing:
Locking the object mutex inside member functions avoids race
conditions between calls to those member functions but not in
between calls to those member functions.
The best way to solve that is by adding 'composite' functions that are doing the job of more than one 'logical' operation. That tends to go against good class design in which you design a logical set of minimal operations and the consuming code combines them.
The alternative is to allow the consuming code access to the mutex. For example expose void lock() const; and void unlock() cont; members. That is usually not preferred because (a) it becomes very easy for consumer code to create deadlocks and (b) you either use a recursive lock (with its overhead) or double up member functions again:
void pop(); //Self locking version...
void pop_prelocked(); //Caller must hold object mutex or program invalidated.
Whether you expose them as public or protected or not that would make try_pop() look something like this:
std::shared_ptr<T> try_pop(){
std::lock_guard<std::mutex> guard(m);
if(empty_prelocked()){
return std::shared_ptr<T>();
}
return pop_prelocked();
}
Adding a mutex and acquiring it at the start of each member is only the start of the story...
Footnote: Hopefully that explains mutual exlusion (mut****ex). There's a whole other topic round memory barriers lurking below the surface here but if you use mutexes in this way you can treat that as an implementation detail for now...
You misunderstand something. You don't need that changeStack function.
If you forget about lock_guard, here's what it looks like (with lock_guard, the code does the same, but lock_guard makes it convenient: makes unlock automatic):
push() {
m.lock();
// do the push
m.unlock();
}
pop() {
m.lock();
// do the pop
m.unlock();
}
When push is called, mutex will be locked. Now, imagine, that on other thread, there is pop called. pop tries to lock the mutex, but it cannot lock it, because push already locked it. So it has to wait for push to unlock the mutex. When push unlocks the mutex, then pop can lock it.
So, in short, it is std::mutex which does the mutual exclusion, not the lock_guard.
I am reading the book "C++ Concurrency In Action" and have some question about the mutex used in listing 6.1, the code snippet is below:
void pop(T& value)
{
std::lock_guard<std::mutex> lock(m);
if(data.empty()) throw empty_stack();
value=std::move(data.top());
data.pop();
}
bool empty() const
{
std::lock_guard<std::mutex> lock(m);
return data.empty();
}
The pop method locks the mutex and then calls the empty mutex. But the mutex is not a recursive_mutex, and the code works properly. So I doubt what is the actually difference between std::mutex and std::recursive_mutex.
It is calling data.empty() which seems like a function from a data member. Not the same as the empty function you show.
If it were, this would be a recursive call
bool empty() const
{
std::lock_guard<std::mutex> lock(m);
return data.empty();
}
and nothing would work.
well, recursive_mutex is for... recursive function!
In some Operating systems, locking the same mutex twice can lead to a system error( in which, the lock may be released copmletely, application may crash and actually all kind of weird and undefined behaviour may occur).
look at this (silly example)
void recursivePusher(int x){
if (x>10){
return;
}
std::lock_guard<std::mutex> lock(m);
queue.push(x);
recursivePusher(x+1);
}
this function recursivly increments x and pushes it into some shared queue.
as we talked above - the same lock may not be locked twice by the same thread, but we do need to make sure the shared queue isn't baing altered by mutilple threads.
one easy solution is to move the lociking outside the recursive function, but what happens if we can't do it? what happens if the function called is the only one that can lock the shared resource?
for example, my calling function may look like this:
switch(option){
case case1: recursivly_manipulate_shared_array(); break;
case case2: recursivly_manipulate_shared_queue(); break;
case case3: recursivly_manipulate_shared_map(); break;
}
ofcourse, you wouldn't lock all three(shred_Array,shared_map,shared_queue) only for one of them will be altered.
the solution is to use std::shared_mutex :
void recursivePusher(int x){
if (x>10){
return;
}
std::lock_guard<std::recursive_mutex> lock(m);
queue.push(x);
recursivePusher(x+1);
}
if the same thread don't need to lock the mutex recursivly it should use regular std::mutex, like in your example.
PS. in your snippet, empty is not the same as T::empty.
calling data.empty() doesn't call empty recursivley.