Thread syncronization with boost::condition_variable - c++

I'm currently using boost 1.55.0, and I cant understand why this code doesn't work.
The following code is a simplification that has the same problem as my program. Small runs finish, but when they are bigger the threads keep waiting forever.
boost::mutex m1;
boost::mutex critical_sim;
int total= 50000;
class krig{
public:
float dokrig(int in,float *sim, bool *aux, boost::condition_variable *hEvent){
float simnew=0;
boost::mutex::scoped_lock lk(m1);
if (in > 0)
{
while(!aux[in-1]){
hEvent[in-1].wait(lk);
}
simnew=1+sim[in-1];
}
return simnew;
};
};
void Simulnode( int itrd,float *sim, bool *aux, boost::condition_variable *hEvent){
int j;
float simnew;
krig kriga;
for(j=itrd; j<total; j=j+2){
if (fmod(1000.*j,total) == 0.0){
printf (" .progress. %f%%\n",100.*(float)j/(float)total);
}
simnew= kriga.dokrig(j,sim, aux, hEvent);
critical_sim.lock();
sim[j]=simnew;
critical_sim.unlock();
aux[j]=true;
hEvent[j].notify_one();
}
}
int main(int argc, char* argv[])
{
int i;
float *sim = new float[total];
bool *aux = new bool[total];
for(i=0; i<total; ++i)
aux[i]=false;
//boost::mutex m1;
boost::condition_variable *hEvent = new boost::condition_variable[total];
boost::thread_group tgroup;
for(i=0; i<2; ++i) {
tgroup.add_thread(new boost::thread(Simulnode, i,sim, aux, hEvent));
}
tgroup.join_all();
return 0;
}
Curiously, I noticed that if I place the code that is inside dokrig() inline in simulnode() then it seems to work. Can it be some problem with the scope of the lock?
Can anybody tell me where I am wrong? Thanks in advance.

The problem happens in this part:
aux[j]=true;
hEvent[j].notify_one();
The first line represents a change of the condition that is being monitored by the hEvent condition variable. The second line proclaims this change to the consumer part, that is waiting for that condition to become true.
The problem is that these two steps happen without synchronization with the consumer, which can lead to the following race:
The consumer checks the condition, which is currently false. This happens in a critical section protected by the mutex m1.
A thread switch occurs. The producer changes the condition to true and notifies any waiting consumers.
Threads switch back. The consumer resumes and calls wait. However, he already missed the notify that occurred in the last step, so he will wait forever.
It is important to understand that the purpose of the mutex that is passed to the wait call of the condition variable is not to protect the condition variable itself, but the condition that it monitors (which in this case is the change to aux).
To avoid the data race, writing to aux and the subsequent notify have to be protected by the same mutex:
{
boost::lock_guard<boost::mutex> lk(m1);
aux[j]=true;
hEvent[j].notify_one();
}

Related

double buffer for consumer and producer problem

So I am trying to implement a double buffer for a typical producer and consumer problem.
1.get_items() basically produces 10 items at a time.
2.producer basically push 10 items onto a write queue. Assume that currently we only have one producer.
3.consumers will consume one item from the queue. There are many consumers.
So I am sharing my code as the following. The implementation idea is simple, consume from the readq until it is empty and then swap the queue pointer, which the readq would point to the writeq now and writeq would now points to the emptied queue and would starts to fill it again. So producer and consumer can work independently without halting each other. This sort of swaps space for time.
However, my code does not work in multiple consumer cases. In my code, I initiated 10 consumer threads, and it always stuck at the .join().
So I am thinking that my code is definitely buggy. However, by examine carefully, I did not find where that bug is. And it seems the code stuck after lk1.unlock(), so it is not stuck in a while or something obvious.
mutex m1;
mutex m2; // using 2 mutex, so when producer is locked, consumer can still run
condition_variable put;
condition_variable fetch;
queue<int> q1;
queue<int> q2;
queue<int>* readq = &q1;
queue<int>* writeq = &q2;
bool flag{ true };
vector<int> get_items() {
vector<int> res;
for (int i = 0; i < 10; i++) {
res.push_back(i);
}
return res;
}
void producer_mul() {
unique_lock<mutex> lk2(m2);
put.wait(lk2, [&]() {return flag == false; }); //producer waits for consumer signal
vector<int> items = get_items();
for (auto it : items) {
writeq->push(it);
}
flag = true; //signal queue is filled
fetch.notify_one();
lk2.unlock();
}
int get_one_item_mul() {
unique_lock<mutex> lk1(m1);
int res;
if (!(*readq).empty()) {
res = (*readq).front(); (*readq).pop();
if ((*writeq).empty() && flag == true) { //if writeq is empty
flag = false;
put.notify_one();
}
}
else {
readq = writeq; // swap queue pointer
while ((*readq).empty()) { // not yet write
if (flag) {
flag = false;
put.notify_one();//start filling process
}
//if (readq->empty()) { //upadted due to race. readq now points to writeq, so if producer finished, readq is not empty and flag = true.
fetch.wait(lk1, [&]() {return flag == true; });
//}
}
if (flag) {
writeq = writeq == &q1 ? &q2 : &q1; //swap the writeq to the alternative queue and fill it again
flag = false;
//put.notify_one(); //fill that queue again if needed. but in my case, 10 item is produced and consumed, so no need to use the 2nd round, plus the code does not working in this simple case..so commented out for now.
}
res = readq->front(); readq->pop();
}
lk1.unlock();
this_thread::sleep_for(10ms);
return res;
}
int main()
{
std::vector<std::thread> threads;
std::packaged_task<void(void)> job1(producer_mul);
vector<std::future<int>> res;
for (int i = 0; i < 10; i++) {
std::packaged_task<int(void)> job2(get_one_item_mul);
res.push_back(job2.get_future());
threads.push_back(std::thread(std::move(job2)));
}
threads.push_back(std::thread(std::move(job1)));
for (auto& t : threads) {
t.join();
}
for (auto& a : res) {
cout << a.get() << endl;
}
return 0;
}
I added some comments, but the idea and code is pretty simple and self-explanatory.
I am trying to figure out where the problem is in my code. Does it work for multiple consumer? Further more, if there are multiple producers here, does it work? I do not see a problem since basically in the code the lock is not fine grained. Producer and Consumer both are locked from the beginning till the end.
Looking forward to discussion and any help is appreciated.
Update
updated the race condition based on one of the answer.
The program is still not working.
Your program contains data races, and therefore exhibits undefined behavior. I see at least two:
producer_mul accesses and modifies flag while holding m2 mutex but not m1. get_one_item_mul accesses and modifies flag while holding m1 mutex but not m2. So flag is not in fact protected against concurrent access.
Similarly, producer_mul accesses writeq pointer while holding m2 mutex but not m1. get_one_item_mul modifies writeq while holding m1 mutex but not m2.
There's also a data race on the queues themselves. Initially, both queues are empty. producer_mul is blocked waiting on flag. Then the following sequence occurs ( P for producer thread, C for consumer thread):
C: readq = writeq; // Both now point to the same queue
C: flag = false; put.notify_one(); // This wakes up producer
**P: writeq->push(it);
**C: if (readq->empty())
The last two lines happen concurrently, with no protection against concurrent access. One thread modifies an std::queue instance while the other accesses that same instance. This is a data race.
There's a data race at the heart of the design. Let's imagine there's just one producer P and two consumers C1 and C2. Initially, P waits on put until flag == false. C1 grabs m1; C2 is blocked on m1.
C1 sets readq = writeq, then unblocks P1, then calls fetch.wait(lk1, [&]() {return flag == true; });. This unlocks m1, allowing C2 to proceed. So now P is busy writing to writeq while C2 is busy reading from readq - which is one and the same queue.

How to make two threads take turns executing their respective critical sections after one thread ends

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.

Why is the lock condition not resolved between two threads using for and while loop

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.

Parallel Dijkstra Deadlocking

I'm using pthreads to try and parallelize Dijkstra's pathfinding algorithm, but I'm running into a deadlock scenario I can't seem to figure out. The gist of it is that every thread has its own priority queue where it gets work (a std::multiset) and a mutex lock corresponding to that queue that is locked whenever it needs to be modified.
Every node has an owner thread which corresponds to the node ID modulo thread count. If a thread is looking through a node's neighbors and updates one of their weights (label) to something lower than it was before, it locks its owner's queue and removes/reinserts (this is to force the set to update its position in the queue). However, this implementation seems to deadlock. I can't tell why though because as far as I can tell, each thread holds only one lock at a time.
Each thread's initial queue contains all of its nodes, but every node's weight besides the source is initialized to ULONG_MAX. If a thread is out of work (it's getting nodes with ULONG_MAX weight from the queue) it just keeps locking and unlocking until another thread gives it work.
void *Dijkstra_local_owner_worker(void *param){
struct thread_args *myargs = ((struct thread_args *)param);
int tid = myargs->tid;
std::multiset<Node *,cmp_label> *Q = (myargs->Q);
struct thread_args *allargs = ((struct thread_args *)param)-tid;
AdjGraph *G = (AdjGraph *)allargs[thread_count].Q;
struct Node *n, *p;
int owner;
std::set<Edge>::iterator it;
Edge e;
pthread_mutex_lock(&myargs->mutex);
while(!Q->empty()){
n = *Q->begin(); Q->erase(Q->begin());
pthread_mutex_unlock(&myargs->mutex);
if(n->label == ULONG_MAX){
pthread_mutex_lock(&myargs->mutex);
Q->insert(n);
continue;
}
for( it = n->edges->begin(); it != n->edges->end(); it++){
e = *it;
p = G->getNode(e.dst);
owner = (int)(p->index % thread_count);
if(p->label > n->label + e.weight){
pthread_mutex_lock(&(allargs[owner].mutex));
allargs[owner].Q->erase(p);
p->label = n->label + e.weight;
p->prev = n;
allargs[owner].Q->insert(p);//update p's position in the PQ
pthread_mutex_unlock(&(allargs[owner].mutex));
}
}
pthread_mutex_lock(&myargs->mutex);
}
pthread_mutex_unlock(&myargs->mutex);
return NULL;
}
Here's the function that spawns the threads.
bool Dijkstra_local_owner(AdjGraph *G, struct Node *src){
G->setAllNodeLabels(ULONG_MAX);
struct thread_args args[thread_count+1];
src->label = 0;
struct Node *n;
for(int i=0; i<thread_count; i++){
args[i].Q = new std::multiset<Node *,cmp_label>;
args[i].tid = i;
pthread_mutex_init(&args[i].mutex,NULL);
}
for(unsigned long i = 0; i < G->n; i++){
n = G->getNode(i); //give all threads their workload in advance
args[(n->index)%thread_count].Q->insert(n);
}
args[thread_count].Q = (std::multiset<Node *,cmp_label> *)G;
//hacky repackaging of a pointer to prevent use of globals
//please note this works and is not the issue. I know it's horrible.
pthread_t threads[thread_count];
for(int i=0; i< thread_count; i++){
pthread_create(&threads[i],NULL,Dijkstra_local_owner_worker,&args[i]);
}
for(int i=0; i< thread_count; i++){
pthread_join(threads[i],NULL);
}
for(int i=0; i< thread_count; i++){
delete args[i].Q;
}
}
The structure definition for each thread's arguments:
struct thread_args{
std::multiset<Node *,cmp_label> *Q;
pthread_mutex_t mutex;
int tid;
};
My question is, where does this code deadlock? I'm getting tunnel vision here so I can't see where I'm going wrong. I've ensured all other logic works, so things like pointer dereferences, etc. are correct.
If a thread is out of work (it's getting nodes with ULONG_MAX weight
from the queue) it just keeps locking and unlocking until another
thread gives it work.
This is a potential problem - once a thread gets into this state, it will essentially hold the mutex locked for the entire duration of its timeslice. pthreads mutexes are lightweight, which means they aren't guaranteed to be fair - it's quite possible (likely, even) that the busy-waiting thread will be able to re-acquire the lock before a woken waiting thread is able to acquire it.
You should use pthread_cond_wait() here, and have the condition variable signalled when another thread updates the queue. The start of your loop would then look something like:
pthread_mutex_lock(&myargs->mutex);
while (!Q->empty())
{
n = *Q->begin();
if (n->label == ULONG_MAX)
{
pthread_cond_wait(&myargs->cond, &myargs->mutex);
continue; /* Re-check the condition after `pthread_cond_wait()` returns */
}
Q->erase(Q->begin());
pthread_mutex_unlock(&myargs->mutex);
/* ... */
and the point where you update another node's queue would look like:
/* ... */
allargs[owner].Q->insert(p); //update p's position in the PQ
pthread_cond_signal(&allargs[owner].cond);
pthread_mutex_unlock(&allargs[owner].mutex);
your code looks something like:
lock()
While(cond)
{
unlock()
if (cond1)
{
lock()
}
for(...)
{
....
}
lock()
}
unlock()
I think it's easy to see you can have problems with this approach depending on the datapath.
I would use the lock only for critical operations:
lock()
Q->erase(..)
unlock()
OR
lock()
Q->insert(..)
unlock()
Try to simplify things and see if that helps

C++ boost thread: having a worker thread pause and unpause based on mutexes/conditions using a concurrent queue

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.