C++ mutex lock declared within or outside for-loop - c++

Given n, below code aims to print "foo", "bar" alternatively.
For example,
Input: n = 2
Output: "foobarfoobar"
Explanation: "foobar" is being output 2 times.
detailed code is listed here. There are two questions:
1) Which one is better, declaring mutex lock outside or inside for-loop?
2) When we declare mutex lock outside the for-loop, why we can NOT call lock.unlock() before cv.notify_one();. It produces runtime error!
class FooBar {
private:
mutex m;
condition_variable cv;
int n;
bool flag = false; // for foo printed
public:
FooBar(int n) {
this->n = n;
}
void foo(function<void()> printFoo) {
//question: can we put here? unique_lock<mutex> lock(m);
for (int i = 0; i < n; i++) {
unique_lock<mutex> lock(m); //question: why shall this lock be declared again and again in each for-loop?
cv.wait(lock, [&](){ return !flag; });
// printFoo() outputs "foo". Do not change or remove this line.
printFoo();
flag = true;
//question: can we call lock.unlock()? yes, it works b/c each for-loop iteration grabs a new lock! if we declare lock outside for-loop, then we can NOT unlock here? why?
lock.unlock();
cv.notify_one();
}
}
void bar(function<void()> printBar) {
for (int i = 0; i < n; i++) {
unique_lock<mutex> lock(m);
cv.wait(lock, [&](){ return flag; }); //wait until lambda returns true
// printBar() outputs "bar". Do not change or remove this line.
printBar();
flag = false;
lock.unlock();
cv.notify_one();
}
}
};```

It doesn't matter where you define unique_lock (inside or outside loop).
All what you need to do is to ensure that mutex is locked when condition_variable::wait is called.
You got runtime error, because when you define unique_lock outside loop
unique_lock<mutex> lock(m); // mutex is LOCKED
for (int ...) {
cv.wait(); // problem is here at second iteratio
lock.unlock();
cv.notify_one();
}
mutex is locked only in first iteration of for (it was locked in ctor of unique_lock).
In second iteration wait is called with unlocked lock, since c++14 it leads std::terminate to be called (
you can read about this behaviour here).
unique_lock has overloaded constructor taking std::defer_lock_t type tag.
When this ctor is called passed mutex is not being locked. Then when you want to "open" critical section
on given mutex you need to call explicitly lock function.
So, the two versions below do the same thing:
1)
unique_lock<mutex> lock(m, std::defer_lock); // mutex is un-locked
for ()
{
lock.lock();
cv.wait(...); // LOCK is locked
lock.unlock();
cv.notify_one();
}
2)
for ()
{
unique_lock<mutex> lock(m); // is locked
cv.wait();
lock.unlock();
cv.notify_one();
}

Related

Correct way to check bool flag in thread

How can I check bool variable in class considering thread safe?
For example in my code:
// test.h
class Test {
void threadFunc_run();
void change(bool _set) { m_flag = _set; }
...
bool m_flag;
};
// test.cpp
void Test::threadFunc_run()
{
// called "Playing"
while(m_flag == true) {
for(int i = 0; i < 99999999 && m_flag; i++) {
// do something .. 1
}
for(int i = 0; i < 111111111 && m_flag; i++) {
// do something .. 2
}
}
}
I wan to stop "Playing" as soon as change(..) function is executed in the external code.
It also wants to be valid in process of operating the for statement.
According to the search, there are variables for recognizing immediate changes, such as atomic or volatile.
If not immediately, is there a better way to use a normal bool?
Actually synchronizing threads safely requires more then a bool.
You will need a state, a mutex and a condition variable like this.
The approach also allows for quick reaction to stop from within the loop.
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <future>
#include <mutex>
class Test
{
private:
// having just a bool to check the state of your thread is NOT enough.
// your thread will have some intermediate states as well
enum play_state_t
{
idle, // initial state, not started yet (not scheduled by OS threadscheduler yet)
playing, // running and doing work
stopping, // request for stop is issued
stopped // thread has stopped (could also be checked by std::future synchronization).
};
public:
void play()
{
// start the play loop, the lambda is not guaranteed to have started
// after the call returns (depends on threadscheduling of the underlying OS)
// I use std::async since that has far superior synchronization with the calling thead
// the returned future can be used to pass both values & exceptions back to it.
m_play_future = std::async(std::launch::async, [this]
{
// give a signal the asynchronous function has really started
set_state(play_state_t::playing);
std::cout << "play started\n";
// as long as state is playing keep doing the work
while (get_state() == play_state_t::playing)
{
// loop to show we can break fast out of it when stop is called
for (std::size_t i = 0; (i < 100l) && (get_state() == play_state_t::playing); ++i)
{
std::cout << ".";
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
}
set_state(play_state_t::stopped);
std::cout << "play stopped.\n";
});
// avoid race conditions really wait for
// trhead handling async to have started playing
wait_for_state(play_state_t::playing);
}
void stop()
{
std::unique_lock<std::mutex> lock{ m_mtx }; // only wait on condition variable in lock
if (m_state == play_state_t::playing)
{
std::cout << "\nrequest stop.\n";
m_state = play_state_t::stopping;
m_cv.wait(lock, [&] { return m_state == play_state_t::stopped; });
}
};
~Test()
{
stop();
}
private:
void set_state(const play_state_t state)
{
std::unique_lock<std::mutex> lock{ m_mtx }; // only wait on condition variable in lock
m_state = state;
m_cv.notify_all(); // let other threads that are wating on condition variable wakeup to check new state
}
play_state_t get_state() const
{
std::unique_lock<std::mutex> lock{ m_mtx }; // only wait on condition variable in lock
return m_state;
}
void wait_for_state(const play_state_t state)
{
std::unique_lock<std::mutex> lock{ m_mtx };
m_cv.wait(lock, [&] { return m_state == state; });
}
// for more info on condition variables
// see : https://www.modernescpp.com/index.php/c-core-guidelines-be-aware-of-the-traps-of-condition-variables
mutable std::mutex m_mtx;
std::condition_variable m_cv; // a condition variable is not really a variable more a signal to threads to wakeup
play_state_t m_state{ play_state_t::idle };
std::future<void> m_play_future;
};
int main()
{
Test test;
test.play();
std::this_thread::sleep_for(std::chrono::seconds(1));
test.stop();
return 0;
}

How does the wait() call get invoked with notify in this code?

I have a c++ code as follows that uses condition-variable for synchronization.
#include <iostream>
#include <condition_variable>
int n = 4;
enum class Turn { FOO, BAR };
Turn turn = Turn::FOO;
std::mutex mut;
std::condition_variable cv;
void foo() {
for (int i = 0; i < n; i++) {
std::unique_lock<std::mutex> lock(mut);
// wait for signal from bar & turn == FOO
cv.wait(lock, [] {return turn == Turn::FOO; });
std::cout << "foo" << std::endl;
// unlock & signal bar
lock.unlock();
turn = Turn::BAR;
cv.notify_one();
}
}
void bar() {
for (int i = 0; i < n; i++) {
std::unique_lock<std::mutex> lock(mut);
// wait for signal from foo & turn == BAR
cv.wait(lock, [] {return turn == Turn::BAR; });
std::cout << "bar" << std::endl;
// unlock & signal foo
lock.unlock();
turn = Turn::FOO;
cv.notify_one();
}
}
int main() {
std::thread thread_1(foo);
std::thread thread_2(bar);
thread_2.join();
thread_1.join();
return 0;
}
The output observed:
Question:
How would the cv.wait(lock, [] {return turn == Turn::FOO; }); inside the foo() get triggered in the beginning?
From what I read, the wait() call with the predicate would be equivalent to:while (!pred()) { wait(lock); }. The predicate is true at the beginning (the initial value of turn is Turn::FOO), but how would the wait call get a notify? Regarding wait(), I see this:
Atomically unlocks lock, blocks the current executing thread, and adds it to the list of threads waiting on *this. The thread will be unblocked when notify_all() or notify_one() is executed. It may also be unblocked spuriously. When unblocked, regardless of the reason, lock is reacquired and wait exits.
But I don't see the other thread's (the one running bar()) to have it's notify_one() executed since turn is still FOO.
How would the cv.wait inside the foo() get triggered in the beginning?
It would be triggered by the predicate evaluating to true. The equivalent loop:
while (!pred()) {
wait(lock);
}
would not call wait() even once (the first time that line of code is visited, anyway).

how condition_variable and unique_lock works for thread safe list

I am trying to use condition variable and unique lock to make a thread safe list. However, I met some problems, it seems the list operation is not thread safe.
I have create an atomic_flag to test if it is thread safe.
Basically, when I operate the list, I will first check if the atomic flag was set, and clear the atomic flag when the list operation is done.
In my thought, the atomic flag operates under the mutex protection, so each time when I test_and_set the atomic flag, I should see the initial value should be false, but when I run the test code, I found it is not so.
Can anyone help me and point out what wrong with the code, why the list operation is not thread safe with the condition variable's protection?
Thanks
The test code is as the following:
using namespace std;
//list element
class myitem
{
public:
myitem() { val = -1; };
myitem(int n, int c){ val = n; chr = c; };
int val;
char chr;
};
// mutex and condition variable to protect the list.
std::mutex mymtx;
condition_variable mycv;
// the list to be protected
std::list<myitem> mylist;
// the atomic flag to test.
std::atomic_flag testlk = ATOMIC_FLAG_INIT;
void datagenthread(char c)
{
int n = 10*1000*1000;
while(n >0)
{
myitem item(n, c);
{
unique_lock<mutex> lk(mymtx); // get the lock
if( testlk.test_and_set() != false) { // test the atomic flag
cout<<"error in thread"<<c<<" for test lock"<<endl;
}
mylist.push_back(item);
testlk.clear(); // clear the atomic before unlock.
}
mycv.notify_one();
n--;
}
}
void datareadthread()
{
int count = 0;
int readc = 0;
while ( count <2) {
{
unique_lock<mutex> lk(mymtx); // acquire lock
while ( mylist.size() <= 0) {
mycv.wait(lk); // block until the thread get notified and get lock again.
}
if( testlk.test_and_set()!= false) {// test the atomic flag.
cout<<"error in reader thread"<<endl;
}
myitem readitem;
readitem = mylist.front();
mylist.pop_front();
readc++;
if ( readitem.val == 1)
{
cout<<" get last one last item form a thread,"<<endl;
count++;
}
testlk.clear(); // clear the atomic flag before unlock
}//unique_lock destruct
}//end while
}
int main()
{
std::thread cons( datareadthread);
std::thread gen1( datagenthread, 'a');
std::thread gen2( datagenthread, 'b');
gen1.join();
gen2.join();
cons.join();
return 0;
}
testlk default constructor initializes it to unspecified state, so at first iteration initial value be something other than false. You should initialize it with cleared state like this:
std::atomic_flag testlk = ATOMIC_FLAG_INIT;
I have found the reason, it seems I link some wrong libs which caused the mutex/condition_var not working properly.

How to say to std::thread to stop?

I have two questions.
1) I want to launch some function with an infinite loop to work like a server and checking for messages in a separate thread. However I want to close it from the parent thread when I want. I'm confusing how to std::future or std::condition_variable in this case. Or is it better to create some global variable and change it to true/false from the parent thread.
2) I'd like to have something like this. Why this one example crashes during the run time?
#include <iostream>
#include <chrono>
#include <thread>
#include <future>
std::mutex mu;
bool stopServer = false;
bool serverFunction()
{
while (true)
{
// checking for messages...
// processing messages
std::this_thread::sleep_for(std::chrono::seconds(1));
mu.lock();
if (stopServer)
break;
mu.unlock();
}
std::cout << "Exiting func..." << std::endl;
return true;
}
int main()
{
std::thread serverThread(serverFunction);
// some stuff
system("pause");
mu.lock();
stopServer = true;
mu.unlock();
serverThread.join();
}
Why this one example crashes during the run time?
When you leave the inner loop of your thread, you leave the mutex locked, so the parent thread may be blocked forever if you use that mutex again.
You should use std::unique_lock or something similar to avoid problems like that.
You leave your mutex locked. Don't lock mutexes manually in 999/1000 cases.
In this case, you can use std::unique_lock<std::mutex> to create a RAII lock-holder that will avoid this problem. Simply create it in a scope, and have the lock area end at the end of the scope.
{
std::unique_lock<std::mutex> lock(mu);
stopServer = true;
}
in main and
{
std::unique_lock<std::mutex> lock(mu);
if (stopServer)
break;
}
in serverFunction.
Now in this case your mutex is pointless. Remove it. Replace bool stopServer with std::atomic<bool> stopServer, and remove all references to mutex and mu from your code.
An atomic variable can safely be read/written to from different threads.
However, your code is still busy-waiting. The right way to handle a server processing messages is a condition variable guarding the message queue. You then stop it by front-queuing a stop server message (or a flag) in the message queue.
This results in a server thread that doesn't wake up and pointlessly spin nearly as often. Instead, it blocks on the condition variable (with some spurious wakeups, but rare) and only really wakes up when there are new messages or it is told to shut down.
template<class T>
struct cross_thread_queue {
void push( T t ) {
{
auto l = lock();
data.push_back(std::move(t));
}
cv.notify_one();
}
boost::optional<T> pop() {
auto l = lock();
cv.wait( l, [&]{ return halt || !data.empty(); } );
if (halt) return {};
T r = data.front();
data.pop_front();
return std::move(r); // returning to optional<T>, so we'll explicitly `move` here.
}
void terminate() {
{
auto l = lock();
data.clear();
halt = true;
}
cv.notify_all();
}
private:
std::mutex m;
std::unique_lock<std::mutex> lock() {
return std::unique_lock<std::mutex>(m);
}
bool halt = false;
std::deque<T> data;
std::condition_variable cv;
};
We use boost::optional for the return type of pop -- if the queue is halted, pop returns an empty optional. Otherwise, it blocks until there is data.
You can replace this with anything optional-like, even a std::pair<bool, T> where the first element says if there is anything to return, or a std::unique_ptr<T>, or a std::experimental::optional, or a myriad of other choices.
cross_thread_queue<int> queue;
bool serverFunction()
{
while (auto message = queue.pop()) {
// processing *message
std::cout << "Processing " << *message << std::endl;
}
std::cout << "Exiting func..." << std::endl;
return true;
}
int main()
{
std::thread serverThread(serverFunction);
// some stuff
queue.push(42);
system("pause");
queue.terminate();
serverThread.join();
}
live example.

unique lock and condition variable - explicitly calling unlock

I found an example code which demonstrates how to use a condition variable :
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <deque>
using namespace std;
deque<int> qu;
mutex mu;
condition_variable cond;
void fun1()
{
int count = 100;
while (count > 0)
{
unique_lock<mutex> locker(mu);
qu.push_front(count);
locker.unlock(); // explicit unlock 1
cond.notify_one();
--count;
}
}
void fun2()
{
int data = 0;
while(data != 1)
{
unique_lock<mutex> locker(mu);
cond.wait(locker, [](){ return !(qu.empty()); });
data = qu.back();
qu.pop_back();
locker.unlock(); // explicit unlock 2
cout<<"data: "<<data<<endl;
}
}
int main()
{
thread t1(fun1);
thread t2(fun2);
t1.join();
t2.join();
system("pause");
return 0;
}
I think that explicitly calling unlock is not necessary. However in fun1 calling it before notify_one might increase a performace, right ? Why unlock is called in fun2 (in each iteration unlock is called implicitly, so doing it explicitly make no sense) ?
std::unique_lock use the RAII pattern.
That means its doesn't need to explicitly call unlock on mutex. This provides exception safety i.e in case of exception after locking the mutex and before explicitly unlocking it it automatically gets unlocked as it goes out of scope.
It seems misleading to me. Locking with a mutex is required to use condition variables. This example uses the same mutex for multiple shared variables (cond and qu).
I think, it will not work properly if fun1 or fun2 runs on more than one thread.
Below would be more clear:
mutex mu;
mutex mu_for_cv;
condition_variable cond;
void fun1()
{
int count = 100;
while (count > 0)
{
unique_lock<mutex> locker(mu);
qu.push_front(count);
{
unique_lock<mutex> locker(mu_for_cv);
cond.notify_one();
}
--count;
}
}
void fun2()
{
int data = 0;
while(data != 1)
{
{
unique_lock<mutex> locker(mu_for_cv);
cond.wait(locker, [](){ return !(qu.empty()); });
}
unique_lock<mutex> locker(mu);
if (!qu.empty())
{
data = qu.back();
qu.pop_back();
cout<<"data: "<<data<<endl;
}
}
}
Also, it'd be better to check the queue is not empty in fun2 to defense against spurious wakeups.