I have a producer thread which produces work for three consumer threads. When work has been produced, the producer thread waits until the consumer threads have finished handling the work. The producer thread then goes on handling the results.
#include <condition_variable>
#include <mutex>
#include <boost/thread/barrier.hpp>
#include <vector>
#include <queue>
std::condition_variable cond;
std::mutex mutex;
boost::barrier barrier(4);
std::vector<std::thread> workers;
std::queue<unsigned int> work;
std::queue<unsigned int> results;
void worker();
int main()
{
// 1 producer and 3 consumers
for(unsigned int i = 0; i < 3; i++)
workers.push_back(std::thread(worker));
// Wait here so the three workers can get to cond.wait();
barrier.wait();
std::unique_lock<std::mutex> lock(mutex);
while(true)
{
// Generate work
std::cout << "gen" << std::endl;
for(unsigned int i = 0; i < 10; i++)
work.push(i);
cond.notify_all();
lock.unlock();
barrier.wait();
// Handle the results
while(results.size() > 0)
results.pop();
lock.lock();
}
return 0;
}
void worker()
{
while(true)
{
std::unique_lock<std::mutex> lock(mutex);
while(results.size() == 0)
{
lock.unlock();
barrier.wait();
lock.lock();
cond.wait(lock);
}
// Get work
unsigned int next = work.front();
work.pop();
// Store the result
results.push(next);
lock.unlock();
}
}
The problem is that I need to make sure that all consumer threads have entered cond.wait(lock) before the producer thread starts its next iteration:
All 4 threads have reached the barrier. The barrier gets released and the threads can continue.
The producer thread locks the mutex before all consumer threads have reached cond.wait(lock). Thus at least one consumer thread is blocked by lock.lock().
The producer thread starts its next iteration, creates work and notifies the consumers. Since at least one consumer thread has not yet reached cond.wait(lock) the notify_all() will be missed by at least one consumer thread. These threads now wait for the next notify_all() - which will never arrive.
The next time the barrier is reached, at least one consumer thread still waits for the next notify_all(). Thus the barrier will not be unlocked and a deadlock occured.
How can I resolve this situation?
A condition_variable should be used together with a flag, to help prevent spurious wake ups. This same flag can also be used to check if the thread should wait at all or just go straight to work.
Add a bool go_to_work=false;, then we simply add it as a predicate in the call to wait and make sure we set/unset it from the main thread.
In main thread before calling notify_all we set our bool
go_to_work=true;
cond.notify_all();
In our worker thread we add the predicate to our wait call
cond.wait(lock, [](){ return go_to_work; });
Lastly, in our main thread we want to set the flag back to false after all work has been done.
barrier.wait();
lock.lock(); // We need to lock the mutex before modifying the bool
go_to_work=false;
lock.unlock();
//Handle result...
Now if a thread reaches the wait call after the main thread has set go_to_work=true it will not wait at all and simply go ahead and do the work. As a bonus this also guards against spurious wake-ups.
Related
I have two file: A,B with rows as csv:timestamp, parameters.. I want to read from one thread one file and from another thread the other file and compare the timestamps in a third thread.
The goal is to construct a vector with the content of the row sorted with the timestamp of both file.
How would you approach this problem?
I did something like this: but it doesn't print out all the timestampsand maybe I'm missing something:
#include <iostream>
#include <fstream>
#include <string>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <vector>
#include <chrono>
std::mutex mtx;
std::condition_variable cv;
long long timestamp1, timestamp2;
std::vector<long long> timestamps;
bool finished1 = false, finished2 = false;
void thread2() {
std::ifstream file2("a.csv");
std::string line;
while (std::getline(file2, line)) {
std::vector<std::string> values = split(line, ',');
long long current_timestamp = std::stoll(values[4]);
{
std::unique_lock<std::mutex> lock(mtx);
while (timestamp1 >= current_timestamp) {
cv.wait(lock);
}
timestamp2 = current_timestamp;
}
cv.notify_one();
}
{
std::unique_lock<std::mutex> lock(mtx);
finished2 = true;
}
cv.notify_one();
}
void thread3() {
while (!finished1 || !finished2) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock);
if (finished1 && finished2) {
break;
}
if (timestamp1 >= timestamp2) {
timestamps.push_back(timestamp1);
std::cout << timestamp1 <<"\n" << std::flush;
} else {
timestamps.push_back(timestamp2);
std::cout << timestamp2 <<"\n" << std::flush;
}
}
}
#include <algorithm>
int main() {
std::thread t1(thread1);
std::thread t2(thread2);
std::thread t3(thread3);
t1.join();
t2.join();
t3.join();
std::cout << std::is_sorted(timestamps.begin(),timestamps.end());
}
The race condition, that result in loss of data, is due to a common misconception that assumes that notifying a condition variable results in an immediate wakeup of any thread that's listening on the condition variable, instantly. Additionally, it's also expected that the woken execution thread is guaranteed to immediately execute all of its assigned tasks, instantly, before it gets blocked on a mutex or a condition variable, again.
This is not the case.
All that notify_one() guarantees is that any execution thread that's listening on the condition variable will be woken up at some point after notify_one() is entered, which may be before or after notify_one() returns. That's it.
So, with that in mind, let's take a look at the sequence of events in thread1 (indentation adjusted):
timestamp1 = current_timestamp;
}
cv.notify_one();
timestamp1 is updated. The mutex is unlocked. The condition variable is notified.
thread3 is now scheduled to be woken up. But you have no guarantees, whatsoever, that not only did it wake up but it also managed to successfully relock the mutex. All you have is a nebulous promises from notify_one that this will happen. Eventually.
Meanwhile, back at the ranch:
std::unique_lock<std::mutex> lock(mtx);
while (timestamp2 >= current_timestamp) {
cv.wait(lock);
}
timestamp1 = current_timestamp;
thread1 managed to read the next timestamp and relock the mutex. Modern CPUs are fast. They can accomplish quite a lot before a context switch to another execution thread. This same thread discovers that the while condition is still true.
Based on the fact that the logic waits until the shared current_timestamp is less than the current value I conclude that the timestamps must be in decreasing order. Well, the last time around the block timestamp2, from the other thread was 1000 and current_timestamp was 900; now, the next current_timestamp is 800. It's still less than 1000, so we proceed on our merry way, updatingcurrent_timestamp from 900 to 800.
Meanwhile, thread3 is still having a nice dream, and only now beginning to wake up from its slumber, as a result of the prior notify_one (which is now just a distant memory to this execution thread). And thread3 missed the 900 value completely. It was replaced by 800. It's gone forever, never to be seen again.
This is not the only flaw in the shown code's logic. The missing data you're seeing is not due to some minor, single oversight, just a few lines of code that needs to be fixed. The logic is flawed in several different ways, that results in the missing data that you're seeing. You will need to completely rework the entire logic if you still want to use this multi-threaded approach to the described task.
In modern C++ with STL threads I want to have two worker threads that take turns doing their work. Only one can be working at a time and each may only get one turn before the other takes a turn. I have this part working.
The added constraint is that one thread needs to keep taking turns after the other thread finishes. But in my code the remaining worker thread deadlocks after the first worker thread finishes. I don't understand why, given that the last things the first worker did was unlock and notify the condition variable, which should've woken the second one up. Here's the code:
{
std::mutex mu;
std::condition_variable cv;
int turn = 0;
auto thread_func = [&](int tid, int iters) {
std::unique_lock<std::mutex> lk(mu);
lk.unlock();
for (int i = 0; i < iters; i++) {
lk.lock();
cv.wait(lk, [&] {return turn == tid; });
printf("tid=%d turn=%d i=%d/%d\n", tid, turn, i, iters);
fflush(stdout);
turn = !turn;
lk.unlock();
cv.notify_all();
}
};
auto th0 = std::thread(thread_func, 0, 20);
auto th1 = std::thread(thread_func, 1, 25); // Does more iterations
printf("Made the threads.\n");
fflush(stdout);
th0.join();
th1.join();
printf("Both joined.\n");
fflush(stdout);
}
I don't know whether this is something I don't understand about concurrency in STL threads, or whether I just have a logic bug in my code. Note that there is a question on SO that's similar to this, but without the second worker having to run longer than the first. I can't find it right now to link to it. Thanks in advance for your help.
When one thread is done, the other will wait for a notification that nobody will send. When only one thread is left, you need to either stop using the condition variable or signal the condition variable some other way.
I am a complete beginner with threads therefore I'm not able to resolve this problem myself.
I have two threads which should run in parallel. The first thread should read in the data (simulate receive queue thread) and once data is ready the second thread shall process (processing thread) the data. The problem is, that the second thread will wait for a change of the conditional variable an infinite amount of time.
If I remove the for loop of the first thread, conditional variable will notify the second thread but the thread will only execute once. Why is the conditional variable not notified if it is used within the for loop?
My goal is to read in all data of a CSV file in the first thread and store it dependent on the rows content in a vector in the second thread.
Thread one look like this
std::mutex mtx;
std::condition_variable condVar;
bool event_angekommen{false};
void simulate_event_readin(CSVLeser leser, int sekunden, std::vector<std::string> &csv_reihe)
{
std::lock_guard<std::mutex> lck(mtx);
std::vector<std::vector<std::string>> csv_daten = leser.erhalteDatenobj();
for (size_t idx = 1; idx < csv_daten.size(); idx++)
{
std::this_thread::sleep_for(std::chrono::seconds(sekunden));
csv_reihe = csv_daten[idx];
event_angekommen = true;
condVar.notify_one();
}
}
Thread two looks like this:
void detektiere_events(Detektion detektion, std::vector<std::string> &csv_reihe, std::vector<std::string> &pir_events)
{
while(1)
{
std::cout<<"Warte"<<std::endl;
std::unique_lock<std::mutex> lck(mtx);
condVar.wait(lck, [] {return event_angekommen; });
std::cout<<"Detektiere Events"<<std::endl;
std::string externes_event_user_id = csv_reihe[4];
std::string externes_event_data = csv_reihe[6];
detektion.neues_event(externes_event_data, externes_event_user_id);
if(detektion.pruefe_Pir_id() == true)
{
pir_events.push_back(externes_event_data);
};
}
}
and my main looks like this:
int main(void)
{
Detektion detektion;
CSVLeser leser("../../Example Data/collectedData_Protocol1.csv", ";");
std::vector<std::string> csv_reihe;
std::vector<std::string> pir_values = {"28161","28211","28261","28461","285612"};
std::vector<std::string> pir_events;
std::thread thread[2];
thread[0] = std::thread(simulate_event_readin, leser, 4, std::ref(csv_reihe));
thread[1] = std::thread(detektiere_events,detektion, std::ref(csv_reihe), std::ref(pir_events));
thread[0].join();
thread[1].join();
}
I'm not a C++ expert, but the code seems understandable enough to see the issue.
Your thread 1 grabs the lock once and doesn't release it until the end of its lifetime. It may signal that the condition is fulfilled, but it never actually releases the lock to allow other threads to act.
To fix this, move std::lock_guard<std::mutex> lck(mtx); inside the loop, after sleeping. This way, the thread will take and release the lock on each iteration, giving the other thread an opportunity to act while sleeping.
I am getting myself familiar with QT5 concurrency library. I was looking at the QWaitCondition example (http://qt-project.org/doc/qt-5.0/qtcore/qwaitcondition.html#details).
Here, one thread (Thread B), reads user input, and all other threads (Thread A) process this input.
Thread A:
forever {
mutex.lock();
keyPressed.wait(&mutex);
++count;
mutex.unlock();
do_something();
mutex.lock();
--count;
mutex.unlock();
}
Thread B:
forever {
getchar();
mutex.lock();
// Sleep until there are no busy worker threads
while (count > 0) {
mutex.unlock();
sleep(1);
mutex.lock();
}
keyPressed.wakeAll();
mutex.unlock();
}
The reason for using count variable and the extensive mutex synchronization is to prevent symbols loss.
The problem is, I think there is still a chance that a symbol will get lost:
imagine the following scenario:
Thread A processes a symbol, and decreases the countes (--count);
the mutex is released; then Thread A stops
Thread B returns from sleep, aquires the mutex, sees, that count ==
0, and calls keyPressed.wakeAll(), and then unlocks the mutex.
However, the wakeAll() call goes to nowhere, since the Thread A is
not waiting.
Thread A starts again, aquaires the mutex and goes into wait().
Since wakeAll() was already called, the symbol is lost.
Am I right, or am I missing something? If I am right, how to correct the example to really prevent it from skipping the symbols?
you are right
to fix this the loop should be entered with the mutex already acquired:
mutex.lock();
forever {
keyPressed.wait(&mutex);
++count;
mutex.unlock();
do_something();
mutex.lock();
--count;
}
mutex.unlock();
I am fairly new to multi-threaded programming, so please forgive my possibly imprecise question. Here is my problem:
I have a function processing data and generating lots of objects of the same type. This is done iterating in several nested loops, so it would be practical to just do all iterations, save these objects in some container and then work on that container in interfacing code doing the next steps. However, I have to create millions of these objects which would blow up the memory usage. These constraints are mainly due to external factors I cannot control.
Generating only a certain amount of data would be ideal, but breaking out of the loops and restarting later at the same point is also impractical. My idea was to do the processing in a separate thread which would be paused after n iterations and resumed once all n objects are completely processed, then resuming, doing n next iterations and so on until all iterations are done. It is important to wait until the thread has done all n iterations, so both threads would not really run in parallel.
This is where my problems begin: How do I do the mutex locking properly here? My approaches produce boost::lock_errors. Here is some code to show what I want to do:
boost::recursive_mutex bla;
boost::condition_variable_any v1;
boost::condition_variable_any v2;
boost::recursive_mutex::scoped_lock lock(bla);
int got_processed = 0;
const int n = 10;
void ProcessNIterations() {
got_processed = 0;
// have some mutex or whatever unlocked here so that the worker thread can
// start or resume.
// my idea: have some sort of mutex lock that unlocks here and a condition
// variable v1 that is notified while the thread is waiting for that.
lock.unlock();
v1.notify_one();
// while the thread is working to do the iterations this function should wait
// because there is no use to proceed until the n iterations are done
// my idea: have another condition v2 variable that we wait for here and lock
// afterwards so the thread is blocked/paused
while (got_processed < n) {
v2.wait(lock);
}
}
void WorkerThread() {
int counter = 0;
// wait for something to start
// my idea: acquire a mutex lock here that was locked elsewhere before and
// wait for ProcessNIterations() to unlock it so this can start
boost::recursive_mutex::scoped_lock internal_lock(bla);
for (;;) {
for (;;) {
// here do the iterations
counter++;
std::cout << "iteration #" << counter << std::endl;
got_processed++;
if (counter >= n) {
// we've done n iterations; pause here
// my idea: unlock the mutex, notify v2
internal_lock.unlock();
v2.notify_one();
while (got_processed > 0) {
// when ProcessNIterations() is called again, resume here
// my idea: wait for v1 reacquiring the mutex again
v1.wait(internal_lock);
}
counter = 0;
}
}
}
}
int main(int argc, char *argv[]) {
boost::thread mythread(WorkerThread);
ProcessNIterations();
ProcessNIterations();
while (true) {}
}
The above code fails after doing 10 iterations in the line v2.wait(lock); with the following message:
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::lock_error> >'
what(): boost::lock_error
How do I do this properly? If this is the way to go, how do I avoid lock_errors?
EDIT: I solved it using a concurrent queue like discussed here. This queue also has a maximum size after which a push will simply wait until at least one element has been poped. Therefore, the producer worker can simply go on filling this queue and the rest of the code can pop entries as it is suitable. No mutex locking needs to be done outside the queue. The queue is here:
template<typename Data>
class concurrent_queue
{
private:
std::queue<Data> the_queue;
mutable boost::mutex the_mutex;
boost::condition_variable the_condition_variable;
boost::condition_variable the_condition_variable_popped;
int max_size_;
public:
concurrent_queue(int max_size=-1) : max_size_(max_size) {}
void push(const Data& data) {
boost::mutex::scoped_lock lock(the_mutex);
while (max_size_ > 0 && the_queue.size() >= max_size_) {
the_condition_variable_popped.wait(lock);
}
the_queue.push(data);
lock.unlock();
the_condition_variable.notify_one();
}
bool empty() const {
boost::mutex::scoped_lock lock(the_mutex);
return the_queue.empty();
}
bool wait_and_pop(Data& popped_value) {
boost::mutex::scoped_lock lock(the_mutex);
bool locked = true;
if (the_queue.empty()) {
locked = the_condition_variable.timed_wait(lock, boost::posix_time::seconds(1));
}
if (locked && !the_queue.empty()) {
popped_value=the_queue.front();
the_queue.pop();
the_condition_variable_popped.notify_one();
return true;
} else {
return false;
}
}
int size() {
boost::mutex::scoped_lock lock(the_mutex);
return the_queue.size();
}
};
This could be implemented using conditional variables. Once you've performed N iterations, you call wait() on the condition variable, and when the objects are processed in another thread, call signal() on the condition variable to unblock the other thread that is blocked on the condition variable.
You probably want some sort of finite capacity queue list or stack in conjunction with a condition variable. When the queue is full, the producer thread waits on the condition variable, and any time a consumer thread removes an element from the queue, it signals the condition variable. That would allow the producer to wake up and fill the queue again. If you really wanted to process N elements at a time, then have the workers signal only when there's capacity in the queue for N elements, rather then every time they pull an item out of the queue.