Trying to make a simple multithreading example using for loops. I'm trying to make them loop in block like this:
Thread 1 printing 0
Thread 2 printing 0
Thread 3 printing 0
Thread 4 printing 0
Thread 1 printing 1
Thread 2 printing 1
Thread 3 printing 1
Thread 4 printing 1
This means: they all print "1", then they all wait for everyone to have done that, then they all print "2", wait again for everyone, print "3", etc.
So I wrote this code:
#include <iostream>
#include <thread>
#include <string.h>
using namespace std;
bool flags[4] = {true,true,true,true};
bool checkAll(){
bool res = false;
for(int i=0;i<4;i++){
res = res|flags[i];
}
return res;
}
void printer(int id){
for(int i=0;i<100;i++){
flags[id] = true;
cout << "Thread: " << id << " printing " << i << endl;
flags[id] = false;
while(checkAll()) {}
}
}
int main(int argc, char *argv[]){
thread t1(printer,0);
thread t2(printer,1);
thread t3(printer,2);
thread t4(printer,3);
t4.join();
t3.join();
t2.join();
t1.join();
return 0;
}
But it doesn't work as expected. As far as I know, it does not work due to concurrency problems (several threads reading/writing the same variable).
So, I tried to solve it using condition variables:
#include <iostream>
#include <thread>
#include <string.h>
#include <mutex>
#include <condition_variable>
using namespace std;
bool flags[4] = {true,true,true,true};
mutex m;
condition_variable g_queuecheck;
bool done = false;
bool checkAll(){
bool res = false;
for(int i=0;i<4;i++){
res = res|flags[i];
}
return res;
}
void printer(int id){
unique_lock<mutex> locker(m);
for(int i=0;i<100;i++){
flags[id] = true;
cout << "Thread: " << id << " printing " << i << endl;
flags[id] = false;
g_queuecheck.wait(locker);
}
}
void controller(){
while(!done){
if(!checkAll()){
g_queuecheck.notify_all();
}
}
}
int main(int argc, char *argv[]){
thread t0(controller);
thread t1(printer,0);
thread t2(printer,1);
thread t3(printer,2);
thread t4(printer,3);
t4.join();
t3.join();
t2.join();
t1.join();
done = true;
t0.join();
return 0;
}
But doesn't work either. So, here come my questions: Is there a possible way of doing it simple like in the first code? If not, what am I doing wrong in the second one? Thanks a lot.
Your examples do not work, because there are race conditions in updating and checking the flags array.
Seems like what you want though is a well known primitive called a barrier. This can be implemented, for example, using semaphores. See section 3.6 of The Little Book of Semaphores for details on how this works.
With a barrier your code can be written concisely as:
Below is a simple semaphore implementation (copied from here).
Using that, you can implement a barrier as in the referenced book: