I am trying to write a ThreadPool/Manager, that can signal threads to do a bunch of work, and then get a callback once done. Unfortunately, if I call signal and wait a few 100 times, it eventually fails. Here is the implementation below:
class ThreadManager{
public:
std::vector<std::thread> threads;
std::vector<bool> threadCompletes;
std::mutex sendMtx, recvMtx, boolLock;
std::condition_variable sendCv;
static std::string printBool(std::vector<bool>& bools){
std::string xx;
for(int i=0; i<bools.size(); i++){
if(bools[i]) xx += "1"; else xx+="0";
}
return xx;
}
static void thread_worker(int id, ThreadManager* manager){
while(1){
std::unique_lock<std::mutex> lck(manager->sendMtx);
//cout << "Thread Wait: " << id << endl;
manager->sendCv.wait(lck);
lck.unlock();
// DO WORK
//std::this_thread::sleep_for(std::chrono::milliseconds(10));
manager->boolLock.lock();
cout << "Start ParOp..: " << id << endl;
manager->boolLock.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
manager->boolLock.lock();
manager->threadCompletes[id] = true;
bool done = (std::find(std::begin(manager->threadCompletes), std::end(manager->threadCompletes), false) == std::end(manager->threadCompletes));
cout << "Job Complete: " << id << " " << printBool(manager->threadCompletes) << endl;
manager->boolLock.unlock();
if(done){
cout << "All Done" << endl;
manager->recvMtx.unlock();
}
}
}
ThreadManager(){
}
void addThread(){
threadCompletes.push_back(false);
threads.push_back(std::thread(ThreadManager::thread_worker, threads.size(), this));
}
void signal(){
boolLock.lock();
for(auto i : threadCompletes) i = 0;
boolLock.unlock();
recvMtx.lock();
std::unique_lock<std::mutex> sendLck(sendMtx);
sendCv.notify_all();
sendLck.unlock();
}
void wait(){
recvMtx.lock();
recvMtx.unlock();
}
void join(){
for (int i = 0; i < threads.size(); ++i) {
threads[i].join();
}
}
};
void test2(){
ThreadManager manager;
for(int i=0; i<8; i++){
manager.addThread();
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
for(int i=0; i<500; i++){
manager.signal();
manager.wait();
cout << "\nComplete: " << i << endl;
}
cout << "ALL DONE" << endl;
manager.join();
}
As you can see from the code, I attempt to loop through signal() and wait(), 500 times. Usually at some random point, one of the threads will fail to receive the wait signal and it will block forever, causing the code to fail. Here is the output:
Complete: 68
Start ParOp..: 0
Start ParOp..: 2
Start ParOp..: 1
Start ParOp..: 6
Start ParOp..: 3
Start ParOp..: 7
Start ParOp..: 4
Start ParOp..: 5
Job Complete: 0 10000000
Job Complete: 2 10100000
Job Complete: 1 11100000
Job Complete: 6 11100010
Job Complete: 7 11100011
Job Complete: 3 11110011
Job Complete: 4 11111011
Job Complete: 5 11111111
All Done
Complete: 69
Start ParOp..: 0
Start ParOp..: 2
Start ParOp..: 1
Start ParOp..: 6
Start ParOp..: 7
Start ParOp..: 3
Start ParOp..: 4
Job Complete: 0 10000000
Job Complete: 2 10100000
Job Complete: 1 11100000
Job Complete: 7 11100001
Job Complete: 4 11101001
Job Complete: 3 11111001
Job Complete: 6 11111011
As you can see, loop 68 was successful, but loop 69 fails, because thread 5 failed to receive a signal, and blocks on the wait forever. Why is this happening
Aucun commentaire:
Enregistrer un commentaire