Hi all,

As explained in another question, I am building a kind of agent platform using Qt. I had some problems with managing thousands of threads and how to have them waiting. So you suggested me programming their actions as slots and invoking them through QTimer::singleshot, so I started with something like this:

VehicleDriver.h
Qt Code:
  1. class VehicleDriver : public Agent
  2. {
  3. Q_OBJECT
  4. public:
  5. VehicleDriver(Vehicle* vehicle = 0)
  6.  
  7. void run();
  8.  
  9. signals:
  10. void updateUI(Agent* agent);
  11.  
  12. protected slots:
  13. // Start the agents behaviour
  14. virtual void started();
  15. void calculateRoute();
  16. void moveToNextRoad();
  17. virtual void ended();
  18.  
  19. private:
  20.  
  21. // Vehicle
  22. Vehicle* vehicle;
  23.  
  24. QList<Road*> route;
  25. Road* current_road;
  26. int pos; // For iterating route
  27. };
To copy to clipboard, switch view to plain text mode 

VehicleDriver.cpp
Qt Code:
  1. #include "VehicleDriver.h"
  2.  
  3. VehicleDriver::VehicleDriver(Vehicle* vehicle){
  4.  
  5. // Vehicle
  6. this->vehicle = vehicle;
  7.  
  8. // Route
  9. this->pos = 0;
  10. this->current_road = 0;
  11.  
  12. // Connect to websocket_server
  13. this->connect( this , SIGNAL(updateUI(Agent*)) , WebSocketServer::getInstance() , SLOT(push(Agent*)) )
  14.  
  15. }
  16.  
  17. void VehicleDriver::run(){
  18. // Move to its own thread
  19. QThread* thread = new QThread();
  20. this->moveToThread( thread );
  21. this->connect( this->thread(), SIGNAL( started() ), this, SLOT( started() ) );
  22. this->thread()->start();
  23. }
  24.  
  25. void VehicleDriver::started(){
  26.  
  27. qDebug() << this->getId() << "STARTED";
  28. QTimer::singleShot( 0 , this , SLOT(calculateRoute()) );
  29. }
  30.  
  31. void VehicleDriver::calculateRoute(){
  32.  
  33. // Calculate route...
  34.  
  35. QTimer::singleShot( 0 , this , SLOT(moveToNextRoad()) );
  36. }
  37.  
  38. void VehicleDriver::moveToNextRoad(){
  39.  
  40. if( this->pos >= this->route.size() ){
  41. QTimer::singleShot(0 , this , SLOT(ended()) );
  42. return;
  43. }
  44.  
  45. // Update stuff
  46.  
  47. this->pos++;
  48. emit updateUI( this );
  49.  
  50. double seconds = // Seconds you would spend travelling through road
  51. QTimer::singleShot( seconds , this , SLOT(moveToNextRoad()) );
  52. }
  53.  
  54. void VehicleDriver::ended(){
  55. qDebug() << this->getId() << "ENDED";
  56. }
To copy to clipboard, switch view to plain text mode 

As you can see, when calling run(), it moves the agent to its own thread and starts calling its slots. However, when running many agents simultaneously, it seems that all these invoked slots are being queued in an unique eventloop and therefore agents need to wait for others to finish executing their slots. Even the websocket message called in emit updateUI( this ); guets queued untill all agents have finished calculating the route.

So my questions are:

Is it possible to have one event loop per thread (per agent) so their slots are queued and executen in their own queue?

Might this happen because I am using the global QTimer::singleshot and it queues slots in an unique queue? Creating a QTimer in every new thread would fix this?

Is this completely wrong and there is a better way to do it?

Thank you very much!