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.
Related
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--;
}
});
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.
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've implemented a simple Producer-Consumer message queue.
#include <chrono>
#include <iostream>
#include <thread>
#include <mutex>
#include <deque>
#define MESSAGE_QUIT 1
struct MessageQueue
{
std::deque<int> message_ids;
std::mutex mutex;
std::condition_variable condition_variable;
};
void SleepFor(int time_in_millis)
{
std::this_thread::sleep_for(std::chrono::milliseconds(time_in_millis));
}
void ProcessMessage(int message_id)
{
std::cout << "Processing Message #" << message_id << '\n';
}
void Producer(MessageQueue *messages)
{
for (int message_id = 10; message_id >= MESSAGE_QUIT; --message_id) {
std::unique_lock<std::mutex> guard(messages->mutex);
messages->message_ids.push_back(message_id);
guard.unlock();
messages->condition_variable.notify_one();
SleepFor(200);
}
}
void Consumer(MessageQueue *messages)
{
int next_message_id = -1;
while (next_message_id != MESSAGE_QUIT) {
std::unique_lock<std::mutex> guard(messages->mutex);
messages->condition_variable.wait(guard);
next_message_id = messages->message_ids.front();
messages->message_ids.pop_front();
guard.unlock();
ProcessMessage(next_message_id);
}
}
int main()
{
MessageQueue messages;
std::thread producer_thread(&Producer, &messages);
std::thread consumer_thread(&Consumer, &messages);
producer_thread.join();
consumer_thread.join();
}
The race condition: in some cases, the condition variable is calling notify_one() in the producer thread while it is not in the waiting state in the consumer thread. How would you solve this? I am not considering the case of spurious waking for now.
Condition variables can spuriously wake up.
messages->condition_variable.wait(guard)
So don't do this. There are other reasons to not do this, including the fact that you can wait on a condition variable when there is data ready.
messages->condition_variable.wait(guard, [&]{return !messages->message_ids().empty();)
This won't wait if there are already messages in the queue. It also deals with spurious wakeups.
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.