PDA

View Full Version : Can I have one EventLoop per thread?



ander.pijoan
22nd July 2015, 10:10
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



class VehicleDriver : public Agent
{
Q_OBJECT
public:
VehicleDriver(Vehicle* vehicle = 0)

void run();

signals:
void updateUI(Agent* agent);

protected slots:
// Start the agents behaviour
virtual void started();
void calculateRoute();
void moveToNextRoad();
virtual void ended();

private:

// Vehicle
Vehicle* vehicle;

QList<Road*> route;
Road* current_road;
int pos; // For iterating route
};



VehicleDriver.cpp



#include "VehicleDriver.h"

VehicleDriver::VehicleDriver(Vehicle* vehicle){

// Vehicle
this->vehicle = vehicle;

// Route
this->pos = 0;
this->current_road = 0;

// Connect to websocket_server
this->connect( this , SIGNAL(updateUI(Agent*)) , WebSocketServer::getInstance() , SLOT(push(Agent*)) )

}

void VehicleDriver::run(){
// Move to its own thread
QThread* thread = new QThread();
this->moveToThread( thread );
this->connect( this->thread(), SIGNAL( started() ), this, SLOT( started() ) );
this->thread()->start();
}

void VehicleDriver::started(){

qDebug() << this->getId() << "STARTED";
QTimer::singleShot( 0 , this , SLOT(calculateRoute()) );
}

void VehicleDriver::calculateRoute(){

// Calculate route...

QTimer::singleShot( 0 , this , SLOT(moveToNextRoad()) );
}

void VehicleDriver::moveToNextRoad(){

if( this->pos >= this->route.size() ){
QTimer::singleShot(0 , this , SLOT(ended()) );
return;
}

// Update stuff

this->pos++;
emit updateUI( this );

double seconds = // Seconds you would spend travelling through road
QTimer::singleShot( seconds , this , SLOT(moveToNextRoad()) );
}

void VehicleDriver::ended(){
qDebug() << this->getId() << "ENDED";
}



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!

anda_skoa
22nd July 2015, 13:59
All QThread's have their own event loop in their default implementation of QThread::run().

So the problem must be elsewhere.

Can you check the currentThread in those methods to see if it is the worker thread or not?

Cheers,
_