I am trying to teach myself multithreading and I followed this tutorial here: https://www.classes.cs.uchicago.edu/archive/2013/spring/12300-1/labs/lab6/
If you scroll all the way to the bottom there is a sample snippet of a producer-consumer and it asks us to solve the race conditions found in this code:
#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <chrono>
#include <queue>
using namespace std;
int main() {
int c = 0;
bool done = false;
queue<int> goods;
thread producer([&]() {
for (int i = 0; i < 500; ++i) {
goods.push(i);
c++;
}
done = true;
});
thread consumer([&]() {
while (!done) {
while (!goods.empty()) {
goods.pop();
c--;
}
}
});
producer.join();
consumer.join();
cout << "Net: " << c << endl;
}
The Net value at the end should be 0, here is my attempt at it:
#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <chrono>
#include <queue>
#include <atomic>
using namespace std;
int main() {
int c = 0;
bool done = false;
queue<int> goods;
mutex mtx;
condition_variable cond_var;
// thread to produce 500 elements
thread producer([&]() {
for (int i = 0; i < 500; ++i) {
// lock critical secion
unique_lock<mutex> lock(mtx);
goods.push(i);
c++;
lock.unlock();
// notify consumer that data has been produced
cond_var.notify_one();
}
// notify the consumer that it is done
done = true;
cond_var.notify_one();
});
// thread to consume all elements
thread consumer([&]() {
while (!done) {
unique_lock<mutex> lock(mtx);
while (!goods.empty()) {
goods.pop();
c--;
}
// unlocks lock and wait until something in producer gets put
cond_var.wait(lock);
}
});
producer.join();
consumer.join();
cout << "Net: " << c << endl;
}
I feel like I am fundamentally missing something. I believe the biggest problem I am having is in the consumer with the cond_var.wait() because if the producer sets "done" to true then the consumer won't go back into the while(!goods.empty()). I am not sure how to fix it though.
Any hints, explanations or even different approaches would be appreciated!
Producer:
thread producer([&]() {
for (int i = 0; i < 500; ++i)
{
{
// Just have a lock while interacting with shared items.
unique_lock<mutex> lock(mtx);
goods.push(i);
c++;
}
cond_var.notify_one();
}
// Lock to update shared state.
unique_lock<mutex> lock(mtx);
done = true;
cond_var.notify_one();
});
Consumer
thread consumer([&]() {
// This loop exits when
// done => true
// AND goods.empty() => true
// Acquire lock before checking shared state.
unique_lock<mutex> lock(mtx);
while (!(done && goods.empty()))
{
// Wait until there is something in the queue to processes
// releasing lock while we wait.
// Break out if we are done or goods is not empty.
cond_var.wait(lock, [&](){return done || !goods.empty();});
// You now have the lock again, so modify shared state is allowed
// But there is a possibility of no goods being available.
// So let's check before doing work.
if (!goods.empty())
{
goods.pop();
c--;
}
}
});
Alternatively if we are simply solving for race condition. We can simply check on the state of done and make sure no other variables have interactions.
Producer:
thread producer([&]() {
// The consumer is not allowed to touch goods
// until you are finished. So just use with
// no locks.
for (int i = 0; i < 500; ++i)
{
goods.push(i);
c++;
}
// Lock to update shared state.
// Tell consumer we are ready for processing.
unique_lock<mutex> lock(mtx);
done = true;
cond_var.notify_one();
});
Consumer
thread consumer([&]() {
// Acquire lock before checking shared state.
unique_lock<mutex> lock(mtx);
cond_var.wait(lock, [&](){return done;});
// We now know the consumer has finished all updates.
// So we can simply loop over the goods and processes them
while (!goods.empty())
{
goods.pop();
c--;
}
});
Related
I'm wanting to have several threads all waiting on a conditional variable (CV) and when the main thread updates a variable they all execute. However, I need the main thread to wait until all these have completed before moving on. The other threads don't end and simply go back around and wait again, so I can't use thread.join() for example.
I've got the first half working, I can trigger the threads, but the main just hangs and doesn't continue. Below is my current code
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
#include <Windows.h>
#define N 3
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
bool finished[N];
void print_id(int id) {
while (1) {
std::unique_lock<std::mutex> lck(mtx); //Try and Lock the Mutex
while (finished[id]) cv.wait(lck); //Wait until finished is false
// ...
std::cout << "thread " << id << '\n';
finished[id] = true; //Set finished to be true. When true, program should continue
}
}
int main()
{
std::thread threads[N];
// spawn 10 threads:
for (int i = 0; i < N; ++i) {
threads[i] = std::thread(print_id, i); //Create n threads
finished[i] = true; //Set default finished to be true
}
std::cout << "N threads ready to race...\n";
for (int i = 0; i < 5; i++) {
std::unique_lock<std::mutex> lck(mtx); //Lock mutex
for (int i = 0; i < N; i++) {
finished[i] = false; //Set finished to false, this will break the CV in each thread
}
cv.notify_all(); //Notify all threads
cv.wait(lck, [] {return finished[0] == true; }); //Wait until all threads have finished (but not ended)
std::cout << "finished, Sleeping for 2s\n";
Sleep(2000);
}
return 0;
}
Thank you.
Edit: I am aware I am only currently checking the status of the finished[0] and not each one. This is done just for simplicity atm and would eventually need to be all of them. I will write a function to manage this later.
You have cv.wait(lck, [] {return finished[0] == true; }); in main thread, but it is not being notified.
You'd need to notify it, and you'd better use another condition_variable for it, not the same as for worker thead notifiecation.
so i want the program to ouput 1\n2\n1\n2\n1\n2\n but it seems to get stuck somewhere. But when i debug it and set a breackpoint at cv1.notify_one() right after declaring t2 it executes ??
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
using namespace std;
mutex cout_lock;
condition_variable cv1, cv2;
mutex mtx1;
unique_lock<std::mutex> lck1(mtx1);
mutex mtx2;
unique_lock<std::mutex> lck2(mtx2);
const int COUNT = 3;
int main(int argc, char** argv)
{
thread t1([&](){
for(int i = 0; i < COUNT; ++i)
{
cv1.wait(lck1);
cout << "1" << endl;
cv2.notify_one();
}
});
thread t2([&](){
for(int i = 0; i < COUNT; ++i)
{
cv2.wait(lck2);
cout << "2" << endl;
cv1.notify_one();
}
});
cv1.notify_one();
t1.join();
t2.join();
return 0;
}
There are several flaws:
You want to guard your output. Therefor you need just one mutex so only one thread can do their work at a time.
You are potentially missing out notifications to your condition variables.
Your global unique_locks aquire the locks of the mutexs in their constructors. So you are holding the locks the whole time and no thread can make progress. Your global unique_locks aquire the locks of the mutexs in their constructors. This is done in the main thread. T1 and T2 are unlocking them through the condition_variable. This is undefined behaviour (thread that owns mutex must unlock it).
This is a recipe to use the condition variable approach correctly:
Have a condition you are interested in. In this case some kind of variable to remember who's turn it is.
Guard this variable by a (ONE!) mutex
Use a (ONE!) condition_variable in conjunction with the mutex of point 2 and the condition of point 1.
This ensures:
There is at any time only one thread which can look and/or change the condition you have.
If a thread is reaching the point in code where it possibly waits for the condition variable, it first checks the condition. Maybe the thread does not even need to go to sleep since the condition he wanna wait for is already true. To do so, the thread has to aquire the mutex, check the condition and decides what to do. While doing so, he owns the lock. The condition cant change because the thread has the lock itself. So you cant miss out a notification.
This leads to the following code ( see live here ):
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
using namespace std;
int main(int argc, char** argv)
{
condition_variable cv;
mutex mtx;
bool runt1 = true;
bool runt2 = false;
constexpr int COUNT = 3;
thread t1([&]()
{
for(int i = 0; i < COUNT; ++i)
{
unique_lock<std::mutex> lck(mtx);
cv.wait(lck, [&](){ return runt1; });
cout << "1" << endl;
runt1 = false;
runt2 = true;
lck.unlock();
cv.notify_one();
}
});
thread t2([&]()
{
for(int i = 0; i < COUNT; ++i)
{
unique_lock<std::mutex> lck(mtx);
cv.wait(lck, [&](){ return runt2; });
cout << "2" << endl;
runt1 = true;
runt2 = false;
lck.unlock();
cv.notify_one();
}
});
t1.join();
t2.join();
return 0;
}
I think you have a data race between your threads starting and the call to cv1.notify_one(); in main().
Consider the case when cv1.notify_one() call happens before thread 1 has started and called cv1.wait(). After that no one calls cv1.notify anymore and your cv-s are just waiting. This is called Lost Wake-up.
You need a mechanism to wait in main till both threads have started, then execute cv1.notify()
Below is an example using int and a mutex.
#include "pch.h"
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
using namespace std;
condition_variable cv1, cv2;
mutex m;
const int COUNT = 3;
enum Turn
{
T1,
T2
};
int main(int argc, char** argv)
{
mutex thread_start_mutex;
int num_started_threads = 0;
Turn turn = T1;
thread t1([&]() {
{
// increase the number of started threads
unique_lock<std::mutex> lck(thread_start_mutex);
++num_started_threads;
}
for (int i = 0; i < COUNT; ++i)
{
// locked cout, unlock before calling notify
{
unique_lock<std::mutex> lck1(m);
// wait till main thread calls notify
cv1.wait(lck1, [&] { return turn == T1;});
cout << "1 a really long string" << endl;
turn = T2; // next it's T2's turn
}
cv2.notify_one();
}
});
thread t2([&]() {
{
// increase the number of started threads
unique_lock<std::mutex> lck(thread_start_mutex);
++num_started_threads;
}
for (int i = 0; i < COUNT; ++i)
{
// locked cout, unlock before calling notify
{
unique_lock<std::mutex> lck2(m);
cv2.wait(lck2, [&] {return turn == T2;});
cout << "2 some other stuff to test" << endl;
turn = T1;
}
cv1.notify_one();
}
});
unique_lock<std::mutex> lck(thread_start_mutex);
// wait until both threads have started
cv1.wait(lck, [&] { return num_started_threads == 2; });
lck.unlock();
cv1.notify_one();
t1.join();
t2.join();
return 0;
}
Also it's unclear why you have two mutexes that are locked outside of main. I usually think of a mutex as something that is protected a resource that should not be accessed concurrently. Seems like the idea was to protect the cout calls, for which you should use one mutex, that each thread will lock, do the cout, unlock and notify the other one.
Edit
My original answer had exact same issue between calls to t1.notify() and t2.wait().
If t1.notify() was called before thread 2 was waiting, thread 2 never got woken up.
To address this I added an enum "Turn" which indicates who's turn it is, and each wait condition now checks if it's their turn or not.
If it is, they are not waiting and just printing out, so even if notify was missed they'd still do their task. If it is not their turn, they'll block until the other thread sets turn variable and calls notify.
NOTE: This demonstrates a good example/practice that it's usually much better to have a condition when using cv.wait(). This both makes intentions clear, and avoids both Lost Wake-up and Spurious Wake-ups.
NOTE 2 this solution might be overly complicated, and in general condition variables and mutexes are unlikely the best approach for this problem.
The other answer is right conceptually but still has another race condition. I ran the code and it would still deadlock.
The issue is that t1 is created, but it does not get to cv1.wait(lck1) until after the cv1.notify_one() executes. Thus your two threads sit together forever waiting. You demonstrate this when you put your breakpoint on that line, allowing the thread to catch up. Also, this issue persists when one thread finishes but doesn't give the other time to call wait() so it just calls notify_one. This can be seen, also fixed* (used loosely), by adding some usleep(100) calls from unistd.h.
See below:
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <unistd.h>
using namespace std;
mutex cout_lock;
condition_variable cv1, cv2;
mutex mtx1;
unique_lock<std::mutex> lck1(mtx1);
mutex mtx2;
unique_lock<std::mutex> lck2(mtx2);
const int COUNT = 3;
int main(int argc, char** argv)
{
thread t1([&](){
for(int i = 0; i < COUNT; ++i)
{
cv1.wait(lck1);
cout << "1\n";
usleep(100);
cv2.notify_one();
}
});
thread t2([&](){
for(int i = 0; i < COUNT; ++i)
{
cv2.wait(lck2);
cout << "2\n";
usleep(100);
cv1.notify_one();
}
});
usleep(1000);
cv1.notify_one();
t1.join();
t2.join();
return 0;
}
EDIT: To do better would be to check for waiting threads, which is not built into the mutexes you use. The proper way might be to create your own mutex wrapper class and include that functionality in the class, but for simplicity sake, I just made a waiting variable.
See below:
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <unistd.h>
using namespace std;
mutex cout_lock;
condition_variable cv1, cv2, cv3;
mutex mtx1;
unique_lock<std::mutex> lck1(mtx1);
mutex mtx2;
unique_lock<std::mutex> lck2(mtx2);
int waiting = 0;
const int COUNT = 3;
int main(int argc, char** argv)
{
thread t1([&](){
for(int i = 0; i < COUNT; ++i)
{
waiting++;
cv1.wait(lck1);
cout << "1\n";
waiting--;
if(!waiting)
usleep(100);
cv2.notify_one();
}
});
thread t2([&](){
for(int i = 0; i < COUNT; ++i)
{
waiting++;
cv2.wait(lck2);
cout << "2\n";
waiting--;
if(!waiting)
usleep(100);
cv1.notify_one();
}
});
if(!waiting)
usleep(100);
cv1.notify_one();
t1.join();
t2.join();
return 0;
}
This code demonstrates that the mutex is being shared between two threads, but one thread has it nearly all of the time.
#include <thread>
#include <mutex>
#include <iostream>
#include <unistd.h>
int main ()
{
std::mutex m;
std::thread t ([&] ()
{
while (true)
{
{
std::lock_guard <std::mutex> thread_lock (m);
sleep (1); // or whatever
}
std::cerr << "#";
std::cerr.flush ();
}
});
while (true)
{
std::lock_guard <std::mutex> main_lock (m);
std::cerr << ".";
std::cerr.flush ();
}
}
Compiled with g++ 7.3.0 on Ubuntu 18.04 4.15.0-23-generic.
The output is a mix of both # and . characters, showing that the mutex is being shared, but the pattern is surprising. Typically something like this:
.......#####..........................##################......................##
i.e. the thread_lock locks the mutex for a very long time. After several or even tens of seconds, the main_lock receives control (briefly) then the thread_lock gets it back and keeps it for ages. Calling std::this_thread::yield() doesn't change anything.
Why are the two mutexes not equally likely to gain the lock, and how can I make the mutex be shared in a balanced fashion?
std::mutex isn't designed to be fair. It doesn't guarantee that the order of locking is kept, you're either lucky to get the lock or not.
If you want more fairness, consider using a std::condition_variable like so :
#include <thread>
#include <mutex>
#include <iostream>
#include <condition_variable>
#include <unistd.h>
int main ()
{
std::mutex m;
std::condition_variable cv;
std::thread t ([&] ()
{
while (true)
{
std::unique_lock<std::mutex> lk(m);
std::cerr << "#";
std::cerr.flush ();
cv.notify_one();
cv.wait(lk);
}
});
while (true)
{
std::unique_lock<std::mutex> lk(m);
std::cerr << ".";
std::cerr.flush ();
cv.notify_one();
cv.wait(lk);
}
}
Making std::mutex fair would have a cost. And in C++ you don't pay for what you don't ask for.
You could write a locking object where the party releasing the lock cannot be the next one to get it. More advanced, you could write one where this only occurs if someone else is waiting.
Here is a quick, untested stab at a fair mutex:
struct fair_mutex {
void lock() {
auto l = internal_lock();
lock(l);
}
void unlock() {
auto l = internal_lock();
in_use = false;
if (waiting != 0) {
loser=std::this_thread::get_id();
} else {
loser = {};
}
cv.notify_one();
}
bool try_lock() {
auto l = internal_lock();
if (in_use) return false;
lock(l);
return true;
}
private:
void lock(std::unique_lock<std::mutex>&l) {
++waiting;
cv.wait( l, [&]{ return !in_use && std::this_thread::get_id() != loser; } );
in_use = true;
--waiting;
}
std::unique_lock<std::mutex> internal_lock() const {
return std::unique_lock<std::mutex>(m);
}
mutable std::mutex m;
std::condition_variable cv;
std::thread::id loser;
bool in_use = false;
std::size_t waiting = 0;
};
it is "fair" in that if you have two threads contending over a resource, they will take turns. If someone is waiting on a lock, anyone giving up the lock won't grab it again.
This is, however, threading code. So I might read it over, but I wouldn't trust my first attempt to write anything.
You could extend this (at increasing cost) to be n-way fair (or even omega-fair) where if there are up to N elements waiting, they all get their turn before the releasing thread gets another chance.
I have this piece of code:
std::unique_lock<std::mutex> lock(m_mutex);
for(;;)
{
// wait for input notification
m_event.wait(lock);
// if there is an input pin doesn't have any data, just wait
for(DataPinIn* ptr:m_in_ports)
if(ptr->m_data_dup==NULL)
continue;
// do work
Work(&m_in_ports,&m_out_ports);
// this might need a lock, we'll see
for(DataPinIn* ptr:m_in_ports)
{
// reduce the data refcnt before we lose it
ptr->FreeData();
ptr->m_data_dup=NULL;
std::cout<<"ptr:"<<ptr<<"set to 0\n";
}
}
in which m_event is a condition_variable.
It waits for notification from another thread and then does some works. But I found out that this only succeeds for the first time and it blocks on m_event.wait(lock) forever, no matter how many times m_event.notify_one() is called. How should I solve this?
Thanks in advance.
You are experiencing the common scenario 'spurious wakeup' (please consult wiki) which condition_variable is desgined to solve.
Please read the sample code in this article: http://www.cplusplus.com/reference/condition_variable/condition_variable/.
Usually condition_variable must be used together with a certain variable to avoid spurious wakeups; that's how the synchronization method is named.
Below is a better piece of sample code:
#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::unique_lock<std::mutex> lock(m);
std::cout << "producing " << i << '\n';
produced_nums.push(i);
notified = true;
cond_var.notify_one();
}
done = true;
cond_var.notify_one();
});
std::thread consumer([&]() {
std::unique_lock<std::mutex> lock(m);
while (!done) {
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();
}
It turns out that a flag variable ruined everything and the threading part is working correctly.
My program has three threads, and I am trying to learn about synchronization and thread safety. Below I outline what the different threads do, but I would like to learn how to use events instead to trigger each process in the different threads instead of infinitely reading (which is giving me concurrency issues).
Googling throws up many options but I'm not sure what is best to implement in this case - could you point the direction to a standard method/event that I could learn to best implement this?
I am doing this on VS 2012, and ideally I would not use external libraries e.g. boost.
Thread 1: receives a message and pushes it into a global queue, queue<my_class> msg_in.
Thread 2: on infinite loop (i.e. while(1) ); waits till if (!msg_in.empty()), does some processing, and pushes it into a global map<map<queue<my_class>>> msg_out.
while (1)
{
if (!msg_in.empty())
{
//processes
msg_map[i][j].push(); //i and j are int (irrelevant here)
}
}
Thread 3:
while (1)
{
if (msg_map.find(i) != msg_map.end())
{
if (!msg_map[i].find(j)->second.empty())
{
//processes
}
}
}
Your problems is a producer consumer problem. You can use condition variables for your events. There is one example of it here: http://en.cppreference.com/w/cpp/thread/condition_variable
I have adapted it to your example if your need it.
#include "MainThread.h"
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
std::mutex m;
std::condition_variable cv;
bool ready = false;
bool processed = false;
void worker_thread(unsigned int threadNum)
{
// Wait until main() sends data
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return ready;});
}
std::cout << "Worker thread "<<threadNum <<" is processing data"<<std::endl;
// Send data back to main()
{
std::lock_guard<std::mutex> lk(m);
processed = true;
std::cout << "Worker thread "<< threadNum <<" signals data processing completed\n";
}
cv.notify_one();
}
int initializeData()
{
// send data to the worker thread
{
std::lock_guard<std::mutex> lk(m);
ready = true;
std::cout << "Data initialized"<<std::endl;
}
cv.notify_one();
return 0;
}
int consumerThread(unsigned int nbThreads)
{
std::atomic<unsigned int> nbConsumedthreads=0;
while (nbConsumedthreads<nbThreads)
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return processed;});
std::cout<<"Data processed counter="<<nbConsumedthreads << " "<< std::endl;
++nbConsumedthreads;
cv.notify_one();
}
return 0;
}
int main()
{
const unsigned int nbThreads=3;
std::thread worker1(worker_thread,1);
std::thread worker2(worker_thread,2);
std::thread worker3(worker_thread,3);
std::thread init(initializeData);
std::thread consume(consumerThread, nbThreads);
worker1.join();
worker2.join();
worker3.join();
init.join();
consume.join();
return 0;
}
Hope that helps, tell me if you need more info.