Ich habe eine n-Körper-Simulation, die ich parallelisiere. Ich verwende QT, also habe ich eine benutzerdefinierte QObject-Klasse mit dem Prozess, den ich parallelisiert habe. Es wird von einem anderen QObject in einem Thread gesteuert, der nur den Thread behandelt. Das Problem ist, dass jedes Mal, wenn ein Objekt mit einem anderen kollidiert, alle Threads gestoppt werden müssen, damit sie gelöscht und mit einem anderen Planetensystem neu erstellt werden können.Fehler beim Beenden eines Threads?
Hier ist die Thread-Handler-Klasse Quelle:
#include "threadhandler.h"
#include <QEventLoop>
#include "subprocess.h"
#include <QThread>
#include <iostream>
#include <vector>
#include <thread>
#include <chrono>
ThreadHandler::ThreadHandler(double scopeX, double scopeY)
{
int size = 100;
int idealNum = QThread::idealThreadCount();
int sizeForEach = size/idealNum;
for(int i = 0 ; i< idealNum ;i++){
SubProcess* tempSub = new SubProcess(i*sizeForEach, (i+1)*sizeForEach, scopeX, scopeY);
QThread* tempThread = new QThread;
tempSub->moveToThread(tempThread);
QEventLoop::connect(tempSub, SIGNAL(finished()), tempThread, SLOT(deleteLater()));
QEventLoop::connect(tempThread, SIGNAL(started()), tempSub, SLOT(process()));
QEventLoop::connect(tempThread, SIGNAL(finished()), tempSub, SLOT(deleteLater()));
QEventLoop::connect(tempSub, SIGNAL(collided()), this,
SLOT(refactorObjects()));
ThreadHandler::threads.push_back(tempThread);
ThreadHandler::objects.push_back(tempSub);
}
}
void ThreadHandler::process(){
std::cout << ThreadHandler::threads.size() << std::endl;
for(int i = 0; i < ThreadHandler::threads.size(); i++){
std::cout << "starting " << i+1 << std::endl;
ThreadHandler::threads.at(i)->start();
}
}
void ThreadHandler::refactorObjects(){
SubProcess::condition = false;
std::this_thread::sleep_for(std::chrono::seconds(1));
for(int i = 0 ; i < ThreadHandler::threads.size() ; i++){
ThreadHandler::threads.at(i)->terminate();
}
ThreadHandler::objects.clear();
SubProcess::sys.push_back(Body::collide(SubProcess::collidedAr.at(0), SubProcess::collidedAr.at(1)));
SubProcess::sys.erase(std::remove(SubProcess::sys.begin(), SubProcess::sys.end(),
SubProcess::collidedAr.at(0)), SubProcess::sys.end());
SubProcess::sys.erase(std::remove(SubProcess::sys.begin(), SubProcess::sys.end(),
SubProcess::collidedAr.at(1)), SubProcess::sys.end());
int idealNum = QThread::idealThreadCount();
int sizeForEach = SubProcess::sys.size()/idealNum;
for(int i = 0 ; i < idealNum ; i++){
SubProcess* tempSub = new SubProcess(i*sizeForEach, (i+1)*sizeForEach);
tempSub->moveToThread(ThreadHandler::threads.at(i));
ThreadHandler::objects.push_back(tempSub);
QEventLoop::connect(tempSub, SIGNAL(finished()), ThreadHandler::threads.at(i), SLOT(deleteLater()));
QEventLoop::connect(ThreadHandler::threads.at(i), SIGNAL(started()), tempSub, SLOT(process()));
QEventLoop::connect(ThreadHandler::threads.at(i), SIGNAL(finished()), tempSub, SLOT(deleteLater()));
QEventLoop::connect(tempSub, SIGNAL(collided()), this,
SLOT(refactorObjects()));
}
for(int i = 0; i < idealNum; i++){
ThreadHandler::threads.at(i)->start();
}
std::cout << "refactored" << std::endl;
}
Hier ist die Unterprozessquelle:
#include "subprocess.h"
#include <iostream>
std::vector<Body> SubProcess::sys;
std::vector<Body> SubProcess::collidedAr;
double SubProcess::timeScale;
bool SubProcess::condition = true;
SubProcess::SubProcess(double start, double end, double scopeX, double scopeY){
for(int i = start; i< end; i++){
SubProcess::sys.push_back(Body::createRandomBody(scopeX, scopeY));
}
this->start = start;
this->end = end;
}
SubProcess::SubProcess(double start, double end){
this->start = start;
this->end = end;
}
void SubProcess::process(){
while(SubProcess::condition){
for(int i = start; i < end ; i++){
for(int j = 0; j < SubProcess::SubProcess::sys.size() ; j++){
if(!(SubProcess::sys.at(i)==SubProcess::sys.at(j))){
double F = Body::getForce(SubProcess::sys.at(i), SubProcess::sys.at(j));
if (F!=-1){
double dX = SubProcess::sys.at(i).getX()-SubProcess::sys.at(j).getX();
double dY = SubProcess::sys.at(i).getY()-SubProcess::sys.at(j).getY();
SubProcess::sys.at(i).exertForce(-dY, -dX, F, timeScale);
} else {
SubProcess::collidedAr.clear();
SubProcess::collidedAr.push_back(SubProcess::sys.at(i));
SubProcess::collidedAr.push_back(SubProcess::sys.at(j));
SubProcess::condition = false;
emit collided();
}
}
}
SubProcess::sys.at(i).tick(timeScale);
}
}
emit finished();
}
Jedes Mal, wenn ich es laufen, es funktioniert perfekt bis zu dem Punkt einer Kollision, wo ich Get:
Was macht mir nicht Sinn ist, dass die Threads am Anfang gelöscht werden g des Refactoring-Prozesses, und das schafft keinen Fehler. Aber aus irgendeinem Grund, nachdem die neuen Threads gestartet wurden, beendet etwas sie. Ich habe keine Ahnung, was hier überhaupt vor sich geht. Ich denke, dass ich die Fäden falsch entsorgere und neu schaffe und dass es eine bessere Methode dafür geben sollte.
Aber wenn ich deleteLater auf ihnen anrufe, wie kann ich sie dann wiederverwenden? Löscht das nicht sie? Oder ist ein vorübergehender Stopp? – Chris
@ user1563074 Sie löschen die Worker-Objekte (die Subprozesse) natürlich nicht die Threads. –
Wenn ich die Threads nicht zerstören/entsorgen muss, dann brauche ich eine benutzerdefinierte Thread-Klasse, die sicherer zu zerstören ist. Außerdem habe ich den obigen Code aktualisiert, und es führt immer noch die gleichen Fehler. – Chris