Mutex does not work as I expect. What is my mistake? - c++

I was trying to figure out the data race theme, and I made this code. Here we work with the shared element wnd. I thought that by putting lock in the while loop, I would prohibit the th1 thread from working with wnd, but this did not happen and I see an unobstructed output of the th1 thread.
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
int main()
{
bool wnd = true;
std::mutex mutex;
std::unique_lock<std::mutex> lock(mutex, std::defer_lock);
std::thread th1([&]() {
int i = 0;
while (true)
{
++i;
if (wnd)
std::cout << i << " WND TRUE" << std::endl;
else
std::cout << i << " WND FALSE" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
});
while (true)
{
lock.lock();
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
if (wnd)
wnd = false;
else
wnd = true;
lock.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
th1.join();
return 0;
}
To tell the truth, I was hoping to see that the th1 thread stops printing for 2+-seconds at a time when the main thread is inside the lock section.

You are not using the mutex and specially std::unique_lock properly.
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
int main()
{
bool wnd = true;
std::mutex mutex;
std::thread th1{[&]() {
for (int i = 0; i<10000; ++i)
{ std::unique_lock<std::mutex> lock(mutex);
std::cout << i << "\tWND\t " << std::boolalpha << wnd << std::endl;
};
}};
for (int i = 0; i<30; ++i)
{ std::unique_lock<std::mutex> lock(mutex);
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
wnd = !wnd;
};
th1.join();
}
std::unique_lock uses its constructor operand as a resource whose acquisition is lock and release is unlock. It is designed to use RAII as a means of guaranteeing correct lock/unlock sequences on mutexes. a defered lock only means the mutex is not locked at the begining of lifespan of the std::unique_lock and it is not the usual use case. You can manually lock/unlock the mutex, but that generally leads to less maintainable, more error-prone code.
Keep in mind that if the threads involved are not racing over the ownership of the mutex, neither waits for the other; in your original prorgram, the worker thread did not touch the mutex. But in the program above, both threads are competing to lock the mutex; winner gets a chance to continue what he wants, and the loser has to wait until the mutex is unlocked - so that he can take its ownership.

Related

If a thread that is blocked on a std::condition_variable is notified, but the lock on the associated mutex has not been released what would be result?

Is it clear what would happen if a thread blocked on a std::condition_variable receives a notification but the lock on the associated mutex is not yet released, and the lock will be released 10 seconds later? Would the thread wait for the lock to be released or is the situation undefined?
I added a 15seconds sleep on purpose to make the lock unavailable during that time to see how waiting thread will be doing. It is doing OK but just wanted to be sure about it.
#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>
struct SharedResource
{
SharedResource() :
cv_mutex(), cv(), counter(0)
{
}
/*
This mutex is used for three purposes:
1) to synchronize accesses to counter
2) to synchronize accesses to std::cerr
3) for the condition variable cv
*/
std::mutex cv_mutex;
std::condition_variable cv;
int counter;
};
void waits(SharedResource& sharedRes)
{
std::unique_lock<std::mutex> lk(sharedRes.cv_mutex);
std::cerr << "Waiting... \n";
while (sharedRes.counter != 1)
{
sharedRes.cv.wait_for(lk,3s);
std::cerr << "Thread ID: " << std::this_thread::get_id() << " wakes up every 3 seconds.\n";
}
std::cerr << "...finished waiting." << "counter: " << sharedRes.counter << std::endl;
} //The lk object will be unlocked after this scope ends.
void signals(SharedResource& sharedRes)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lk(sharedRes.cv_mutex);
std::cerr << "Notifying...\n";
} // The lk object will be unlocked after this scope ends.
sharedRes.cv.notify_all();
std::this_thread::sleep_for(std::chrono::seconds(6));
{
std::lock_guard<std::mutex> lk(sharedRes.cv_mutex);
sharedRes.counter = 1;
std::cerr << "Notifying again...\n";
sharedRes.cv.notify_all();
std::this_thread::sleep_for(std::chrono::seconds(15));
}// The lk object will be unlocked after this scope ends.
}
int main()
{
SharedResource sharedRes;
std::thread
t1(waits, std::ref(sharedRes)),
t2(signals, std::ref(sharedRes));
t1.join();
t2.join();
}
If a thread that is blocked on a std::condition_variable is notified, but the lock on the associated mutex has not been released what would be result?
It will continue to wait / wait_for until it can reacquire the lock.
When std::condition_variable::wait and wait_for returns (for whatever reason), the lock is held again, so you don't have to worry about that.
It can even return from wait without having gotten any notifications (spurious wake-ups) - but, no matter what, the lock is reacquired when the call returns.

program went into dead lock using condition variable in c++11

I am currently trying to learn how to use a condition_variable for thread synchronization. For testing, I have made the demo application shown below. When I start it, it runs into a dead lock. I know the location where this happens, but I'm unable to understand why the deadlock occurs.
I know that a condition_variable's wait function will automatically unlock the mutex when the condition is not true, so the main thread should not be blocked in the second pass. But it is just this what happens.
Could anybody explain why?
#include <thread>
#include <condition_variable>
#include <iostream>
bool flag = false;
std::mutex g_mutex;
std::condition_variable cv;
void threadProc()
{
std::unique_lock<std::mutex> lck(g_mutex);
while (true)
{
static int count = 0;
std::cout << "wait for flag" << ++count << std::endl;
cv.wait(lck, []() {return flag; }); // !!!It will blocked at the second round
std::cout << "flag is true " << count << std::endl;
flag = false;
lck.unlock();
}
}
int main(int argc, char *argv[])
{
std::thread t(threadProc);
while (true)
{
static int count = 0;
{
std::lock_guard<std::mutex> guard(g_mutex); // !!!It will blocked at the second round
flag = true;
std::cout << "set flag " << ++count << std::endl;
}
cv.notify_one();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
t.join();
return 0;
}
I know that a condition_variable's wait function will automatically unlock the mutex when the condition is not true.
Um..., yes..., Just to be absolutely clear, cv.wait(lck, f) does this:
while(! f()) {
cv.wait(lck);
}
And each call to cv.wait(lck) will;
unlock lck,
wait until some other thread calls cv.notify_one() or cv.notify_all(),
re-lock lck, and then
return.
You can fix the problem by moving the unique_lock(...) statement inside the while loop. As it is now, you're attempting to unlock lck on round 2 but it was not in a locked state, since, after round 1 you never locked it again.

Producer/consumer, consumer thread never executed

Created a program having a producer thread and a consumer thread.
The producer thread continuously pushes to a stack every one second, which is protected by a mutex.
The consumer thread continuously pops from the stack.
The unexpected behavior is that, the producer thread is constantly running, while the consumer thread never gets a chance to pop the stack.
How could I proceed to investigate this problem? Many thanks.
#include <stack>
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
std::mutex mtx;
std::stack<int> the_stack;
void producer(const int id)
{
while(1)
{
mtx.lock();
the_stack.push(0);
std::cout << "Producer " << id << " push" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
mtx.unlock();
}
}//producer
void consumer(const int id)
{
while(1)
{
mtx.lock();
if (!the_stack.empty())
{
std::cout << "Consumer " << id << " pop" << std::endl;
the_stack.pop();
}
mtx.unlock();
}
}//consumer
int main()
{
std::thread thread_0(producer, 0);
std::thread consum_0(consumer, 0);
thread_0.join();
consum_0.join();
return 0;
}//main;
The producer is spending its sleeping time while holding the mutex.
This hardly gives the consumer a chance to lock the mutex.
If you put the sleep statement outside the mutex protected area, it will work as expected..
void producer(const int id)
{
while(1)
{
....
mtx.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1)); // below the unlock operation
}

C++14 thread/condition variable misunderstanding

I'm trying to run a thread with a function from a class member and use conditional variable to wait until the main thread signals and add the times the thread got signaled. Here is the code:
// Example program
#include <iostream>
#include <string>
#include <atomic>
#include <thread>
#include <unistd.h>
#include <mutex>
#include <condition_variable>
std::mutex m_mutex;
std::condition_variable m_condVar;
char stop =0;
class dummclass
{
std::thread dummclass_thread;
int alarms;
public:
dummclass() :
alarms(0),
dummclass_thread(std::thread(&dummclass::dummclassThreadProc, this))
{
}
~dummclass()
{
std::cout<<"Alarms: "<<alarms<<"\n";
//signal thread before joining
{
std::lock_guard<std::mutex> lock_guard(m_mutex);
stop=1;
}
m_condVar.notify_one();
dummclass_thread.join();
}
private:
void dummclassThreadProc()
{
{
std::unique_lock<std::mutex> mlock(m_mutex);
std::cout<<"thread waiting\n";
m_condVar.wait(mlock);
std::cout<<"thread done waiting\n";
}
sleep(1);
std::unique_lock<std::mutex> mlock(m_mutex);
while (!stop)//!stop_dummclass.load())
{
std::cout<<"got mutex\n";
m_condVar.wait(mlock);
std::cout<<"wait done\n";
{
std::cout<<"got one\n";
alarms++;
}
}
std::cout<<"end loop\n";
}
};
int main()
{
dummclass *x = new dummclass;
sleep(3);
{
std::lock_guard<std::mutex> lock_guard(m_mutex);
}
m_condVar.notify_one();
std::cout<<"done waiting\n";
sleep(3);
for(int i=0;i<13;i++)
{
{
std::cout<<"signal "<<i<<"\n";
std::lock_guard<std::mutex> lock_guard(m_mutex);
}
m_condVar.notify_one();
}
delete x;
}
The weird part is that the initial waiting and signaling that are outside of the loops actually work ok. I don't understand what mistake I do so that the while loop inside the class thread doesn't catch any signal from the main thread but it catches a signal from the destructor of the dummyclass when I delete it. This is the output:
thread waiting
done waiting
thread done waiting
got mutex
signal 0 signal 1 signal 2 signal 3 signal 4 signal 5 signal 6 signal 7 signal
8 signal 9 signal 10 signal 11 signal 12
Alarms: 0
wait done
got one end loop
EDIT: It seems that adding a 1 second sleep in the main() for loop solves the problem. Is it possible that the for loop gets the mutex before wait() manages to wake and lock the mutex ?
for(int i=0;i<13;i++)
{
{std::cout<<"signal "<<i<<"\n";
std::lock_guard<std::mutex> lock_guard(m_mutex);}
m_condVar.notify_one();
sleep(1);
}
Can someone please show me what is wrong ?
Thanks.
The object doing the waiting gets deleted before it processes the signal. Since the delete happens on a known to be running thread it has a fair chance to get executed first. In particular it is also likely to reacquire the lock again: Since the notify_one() is done while the mutex is locked the wait()ing thread cannot acquire it and will go back to sleep, waiting for the mutex to be released. That gives the signalling thread an opportunity to reacquire the lock. The only forced synchronizqtion causing the signalling thread to wait is the join() and it does give the waiting thread a chance to execute.
Note that signals of condition variables are not something delivered to the waiting thread. They are essentially wake-up calls. The waiting thread will wake up eventually once a signal is delivered. However, many signals can be delivered before it actually does so.
I don't understand what mistake I do so that the while loop inside the
class thread doesn't catch any signal from the main thread
Even though multiple notifications are sent the thread may only receive a single notification.
The notify_one() call does
not mean that the current thread will stop and wait for another thread.
It just means that the other thread must wake up at some point because something may have happened that it would be interested in.
Also note that std::condition_variable::wait could experience a spurious wakeup, so it might not even have anything to do or have received a 'real' signal.
The solution is to provide a predicate as a parameter to the wait() call. The predicate can then check if there is a signal (via a variable provided for this purpose and only changed under lock) and may also check if the program has been stopped.
In the updated program below I've added a predicate to the wait and made some minor changes. The program only notifies under lock, but you might choose not to.
// Example program - modified
#include <iostream>
#include <string>
#include <atomic>
#include <thread>
//#include <unistd.h>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::mutex m_mutex;
std::condition_variable m_condVar;
bool signal_waiting{false};
bool stop{false};
class dummclass
{
int alarms{};
std::thread dummclass_thread{[this](){dummclassThreadProc(); }};
public:
~dummclass()
{
std::cout << "Alarms: " << alarms << "\n";
//signal thread before joining
{
std::lock_guard<std::mutex> lock_guard(m_mutex);
stop = 1;
m_condVar.notify_one();
}
dummclass_thread.join();
}
private:
void dummclassThreadProc()
{
{
std::unique_lock<std::mutex> mlock(m_mutex);
std::cout << "thread waiting\n";
m_condVar.wait(mlock);
std::cout << "thread done waiting\n";
}
std::this_thread::sleep_for(std::chrono::seconds{1});
while(!stop)//!stop_dummclass.load())
{
std::unique_lock<std::mutex> mlock(m_mutex);
std::cout << "got mutex\n";
//m_condVar.wait(mlock);
m_condVar.wait(mlock, [](){return signal_waiting || stop; });
if(stop)
break;
std::cout << "wait done\n";
std::cout << "got one\n";
alarms++;
signal_waiting = false;
m_condVar.notify_one();
}
std::cout << "end loop\n";
}
};
int main()
{
dummclass *x = new dummclass;
//sleep(3);
std::this_thread::sleep_for(std::chrono::seconds{1});
{
std::lock_guard<std::mutex> lock_guard(m_mutex);
m_condVar.notify_one();
}
std::cout << "done waiting\n";
//sleep(3);
std::this_thread::sleep_for(std::chrono::seconds{1});
for(int i = 0; i<13; i++)
{
{
std::cout << "signal " << i << "\n";
std::unique_lock<std::mutex> lock(m_mutex);
m_condVar.wait(lock, [](){return !signal_waiting ; });
signal_waiting = true;
m_condVar.notify_one();
}
}
delete x;
}

Understanding the example of using std::condition_variable

There is example of using condition_variable taken from cppreference.com:
#include <condition_variable>
#include <mutex>
#include <thread>
#include <iostream>
#include <queue>
#include <chrono>
int main()
{
std::queue<int> produced_nums;
std::mutex m;
std::condition_variable cond_var;
bool done = false;
bool notified = false;
std::thread producer([&]() {
for (int i = 0; i < 5; ++i) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::lock_guard<std::mutex> lock(m);
std::cout << "producing " << i << '\n';
produced_nums.push(i);
notified = true;
cond_var.notify_one();
}
std::lock_guard<std::mutex> lock(m);
notified = true;
done = true;
cond_var.notify_one();
});
std::thread consumer([&]() {
while (!done) {
std::unique_lock<std::mutex> lock(m);
while (!notified) { // loop to avoid spurious wakeups
cond_var.wait(lock);
}
while (!produced_nums.empty()) {
std::cout << "consuming " << produced_nums.front() << '\n';
produced_nums.pop();
}
notified = false;
}
});
producer.join();
consumer.join();
}
If variable done comes true before the consumer thread is started, the consumer thread will not get any message. Indeed, sleep_for(seconds(1)) almost avoids such situation, but could it be possible in theory (or if don't have sleep in code)?
In my opinion correct version should look like this to force running consumer loop at least once:
std::thread consumer([&]() {
std::unique_lock<std::mutex> lock(m);
do {
while (!notified || !done) { // loop to avoid spurious wakeups
cond_var.wait(lock);
}
while (!produced_nums.empty()) {
std::cout << "consuming " << produced_nums.front() << '\n';
produced_nums.pop();
}
notified = false;
} while (!done);
});
Yes, you are absolutely right: there is a (remote) possibility that the consumer thread will not start running until after done has been set. Further, the write to done in the producer thread and the read in the consumer thread produce a race condition, and the behavior is undefined. Same problem in your version. Wrap the mutex around the entire loop in each function. Sorry, don't have the energy to write the correct code.