Meine Anwendung besteht aus zwei Threads:
- GUI-Thread (unter Verwendung von Qt)
- Simulationsthread
Der Grund für die Verwendung von zwei Threads ist, dass die GUI reaktionsschnell bleiben soll, während der Sim-Thread so schnell wie möglich laufen soll.
In meinem GUI-Thread rendere ich die Entitäten in der Simulation mit einer FPS von 30-60; ich möchte jedoch, dass meine Simulation sozusagen "vorauseilt" und den Spielstatus in eine Warteschlange stellt, um irgendwann gezeichnet zu werden (denken Sie an Streaming-Video, Sie haben einen Puffer).
Nun benötige ich für jedes Bild der Simulation, das ich rendern möchte, den entsprechenden Simulations-"Status". Mein Sim-Thread sieht also etwa so aus:
while(1) {
simulation.update();
SimState* s = new SimState;
simulation.getAgents( s->agents ); // store agents
// store other things to SimState here..
stateStore.enqueue(s); // stateStore is a QQueue<SimState*>
if( /* some threshold reached */ )
// push stateStore
}
SimState
sieht so aus:
struct SimState {
std::vector<Agent> agents;
//other stuff here
};
Und Simulation::getAgents sieht so aus:
void Simulation::getAgents(std::vector<Agent> &a) const
{
// mAgents is a std::vector<Agent>
std::vector<Agent> a_tmp(mAgents);
a.swap(a_tmp);
}
Les Agent
s selbst sind recht komplexe Klassen. Die Mitglieder sind ein Bündel von int
s und float
s und zwei std::vector<float>
s.
Mit der aktuellen Konfiguration kann der Simulator nicht schneller crunchen als der GUI-Thread zeichnet. Ich habe überprüft, dass der aktuelle Engpass ist simulation.getAgents( s->agents )
Denn selbst wenn ich die Push-Funktion weglasse, sind die Aktualisierungen pro Sekunde langsam. Wenn ich diese Zeile auskommentiere, sehe ich eine Verbesserung der Aktualisierungen pro Sekunde um mehrere Größenordnungen.
Welche Art von Containern sollte ich also verwenden, um den Zustand der Simulation zu speichern? Ich weiß, es ist ein Bündel von Kopieren geht atm, aber einige davon ist unvermeidlich. Sollte ich speichern Agent*
im Vektor anstelle von Agent
?
Anmerkung: In Wirklichkeit befindet sich die Simulation nicht in einer Schleife, sondern verwendet Qt's QMetaObject::invokeMethod(this, "doSimUpdate", Qt::QueuedConnection);
damit ich Signale/Slots zur Kommunikation zwischen den Threads verwenden kann; ich habe jedoch eine einfachere Version mit while(1){}
und das Problem bleibt bestehen.