PDA

View Full Version : QThread - multi threaded signals and slots



rishid
28th March 2008, 06:03
Hi,

I am trying to figure out how to emit a signal from one my threads to another thread, both non-gui threads. I see in the Qt documentation it is possible, I just cannot figure it out.

Seems like I need something like, I am just not sure in the NetReceive class.
connect(this, SIGNAL(checkNetQueue()), <ptr to other thread>, SLOT(processNetQueue()), Qt::QueuedConnection);

Here is a little background on how my classes are setup:
NetworkThread is a abstract parent class and I have two children from that thread, NetThread and NetReceiveThread. I want NetReceiveThread to emit a signal to the NetThread. If I emit the signal from NetThread itself, the slot executes and works fine.

The threads are created in my Main GUI window as class variables, like NetThread t1, NetReceiveThread t2. And then start() is called on each of them inside the MainWin constructor.

Any ideas you can come up? I appreciate the help.

Thanks so much.
RishiD

---------------------------------------------------------------------

Here are some small snippets of my three thread headers.

NetworkThread.h


class NetworkThread : public QThread
{
Q_OBJECT
public:
NetworkThread() { };
signals:
void checkNetQueue();

};


NetThread.h


class NetThread : public NetworkThread
{
Q_OBJECT
public:
NetThread();

protected:
void run()
{
// emitting checkNetQueue() works fine, if the emit is run inside the NetThread
connect(this, SIGNAL(checkNetQueue()), this, SLOT(processNetQueue()));
exec();
}

private slots:
void processNetQueue();
}




NetReceiveThread.h


class NetReceiveThread : public NetworkThread
{
Q_OBJECT
public:
NetReceiveThread(){}
protected:
void run()
{
// need to change the second this, to a pointer to NetThread
// connect(this, SIGNAL(checkNetQueue()), this, SLOT(processNetQueue()),
// Qt::QueuedConnection);
receiveLoop() // <--- calls emit checkNetQueue();
}


};

jpn
29th March 2008, 22:30
Make

connect(this, SIGNAL(checkNetQueue()), this, SLOT(processNetQueue()));
use direct connection instead:

connect(this, SIGNAL(checkNetQueue()), this, SLOT(processNetQueue()), Qt::DirectConnection);

Otherwise the signal gets queued and processNextQueue() gets called in "wrong" thread context (because QThread lives in the creator thread, which is not same as QThread::run()).

rishid
29th March 2008, 22:41
Ok, that will fix that problem I was having where the QThread was actually calling the processNetQueue() which I did not want. I wanted the NetThread instance to take care of it.

But for the receive thread, should I used a Queued connection or Direct? Right now it is working with Queued, but once again QThread is calling the slot. I am assuming I should change this to Direct?

The code below is how I have it in the receive thread run() method. Where netThread is a pointer to the NetThread object that is created in the MainWin.

Thanks for the help, once again jpn.



connect(this, SIGNAL(checkNetQueue()), netThread,
SLOT(processNetQueue()), Qt::QueuedConnection);

jpn
29th March 2008, 22:46
There's the problem. Slots in QThread subclasses are very problematic. QThread object itself lives in different thread than QThread::run() is executed. Slots get called in the thread context where the receiver QObject lives. You can't fix it by changing connection type. I recommend you don't do anything else but allocate an object with required slots on the stack and call exec() in QThread::run(). This object will live in the worker thread and receive signals like you want.


class MyThread : public QThread
{
...
void run()
{
Receiver recv; // <-- this object lives in the worker thread and receives signals "correctly"
...
exec();
}
...
}

rishid
30th March 2008, 01:47
Alright that does make sense. Time to restructure all my objects and threads, will report back if I have any problems.

Thanks