PDA

View Full Version : QThread sends signal to main thread immediatly



BIllNo123
26th August 2010, 16:53
Is there a way that the signal a QThread sends to main thread is received immediately (and not queued)?
I mean that if a thread signals then the main thread will receive it AFTER it has done its own work (using the thread-safe connection type QueuedConnection).

Talei
26th August 2010, 17:30
Look into Qt::DirectConnection, or enum Qt::ConnectionType.

tbscope
27th August 2010, 06:29
Look into Qt::DirectConnection, or enum Qt::ConnectionType.

Oh oh :-)
That will not work ;-)

If you use multiple threads, you have to use a queued connection.

Talei
27th August 2010, 08:02
Oh oh :-)
That will not work ;-)

If you use multiple threads, you have to use a queued connection.

Is it really that funny? Or maybe I made some basic/noob mistake?
I simply pointed out that there is a posibility of using DirectConnection and thread poster should check it out.

About thread what about that connection configuration?

connect( th, SIGNAL( started() ), thObj, SLOT(doJob()), Qt::QueuedConnection ); //start thObj
connect( thObj, SIGNAL( finThObj( int ) ), this, SLOT(thJobFin(int)), Qt::DirectConnection ); //job done Direct ret
connect( thObj, SIGNAL( thObjQuit() ), th, SLOT(quit()), Qt::QueuedConnection ); // queued quit
connect( th, SIGNAL( finished() ), this, SLOT(thQuit()), Qt::QueuedConnection ); //clean up i.e. delete th and thObj

Everything, except finThObj(int), is queued. finThObj(), in my opinion (please correct me if I'm wrong), should return immediately after execution.

And in thObj job I did this:


void objThDirConn::doJob()
{
qDebug() << "thread job: in " << this->thread();

int k = 0;
for( int i = 0; i < 1000000000; ++i)
{
k++;
}

emit finThObj( k );
emit thObjQuit();
}

And if I use QList<QThread> and run i.e. 4 thread it still should work, or maybe I'm mistaken here?.

Ofcourse my implementation don't work on the shared data.

Full example code
5099

tbscope
27th August 2010, 08:21
Is it really that funny? Or maybe I made some basic/noob mistake?
I simply pointed out that there is a posibility of using DirectConnection and thread poster should check it out.
Sorry, I never have the intention to insult someone.

You can not use direct connections with multiple threads. Yes, it will work most of the time or sometimes. No, you will not be sure of the results.


Be aware that using direct connections when the sender and receiver live in different threads is unsafe if an event loop is running in the receiver's thread, for the same reason that calling any function on an object living in another thread is unsafe.


In other words, you send a signal in thread 1 while a slot in thread 2 is connected to it. You need to wait till the program gets to the event loop of thread 2 to handle the slot. If you use a direct connection, thread 2 will not be in its event loop, resulting in problems.

All is fine when you have only one event loop. But with multiple event loops, you need to wait.

BIllNo123
27th August 2010, 10:12
Talei what about putting the "emit finThObj( k );" in the for-loop?

BIllNo123
27th August 2010, 10:13
Here is my example:

//MyThread.h file
#include <QtGui>
#include <iostream>


class MyThread : public QThread
{
Q_OBJECT

public:
MyThread ();
void run();

signals:
void Signal_AppendTextThread(QString);


protected slots:
void Slot_ShowMessage(QString);

};


//MyThread.cpp file
#include "MyThread.h"


MyThread::MyThread(): QThread()
{
}

void MyThread:Slot_ShowMessage(const std::string &text)
{
}

void MyThread::run()
{

for(int i=1;i<100;i++)
{
emit Signal_AppendTextThread("emitting thread signal ");
}

exec(); //do i really need this?
}


// MyMainWindow.h file

#include <QtGui/QMainWindow>
#include <QtGui/QApplication>
#include <QtGui/QLineEdit>
#include "MyThread.h"



class MyMainWindow: public QMainWindow
{
Q_OBJECT

public:
MyMainWindow( QWidget * pParent = 0);
~MyMainWindow();

MyThread m_pApplyAlgorithmThread;
QTextEdit *m_pTextEdit;

protected slots:
void Slot_ShowMessage(QString);

};



//MyMainWindow.cpp file

#include "MyMainWindow.h"

MyMainWindow::MyMainWindow( QWidget * pParent) :
QMainWindow( pParent )
{

setWindowTitle( "Thread Test" );

m_pTextEdit = new QTextEdit(this);
m_pTextEdit->setReadOnly(true);
m_pTextEdit->setGeometry(0,0,200,200);


m_pApplyAlgorithmThread.start();

connect(&m_pApplyAlgorithmThread, SIGNAL(Signal_AppendTextThread(QString)),
this, SLOT(Slot_ShowMessage(QString)),Qt::QueuedConnecti on );


showMaximized();

for(int i=1;i<100;i++)
{
m_pTextEdit->append("main");
m_pTextEdit->repaint();

}
}

MyMainWindow::~MyMainWindow()
{
}

void MyMainWindow::Slot_ShowMessage(QString)
{
m_pTextEdit->append(text.c_str());
m_pTextEdit->repaint();
}


It prints out
main
main
.
.
.
main //#100 th time
emitting thread signal
emitting thread signal
.
.
.
emitting thread signal //#100 th time

I want the thread to emit the signal and the signal to be "executed" by main's slot immediately
(*something* like this)
main
main
.
.
.
emitting thread signal //thread emitted signal and "executed" by main's slot
emitting thread signal //thread emitted signal and "executed" by main's slot
emitting thread signal //thread emitted signal and "executed" by main's slot
emitting thread signal //thread emitted signal and "executed" by main's slot
.
.
.
emitting thread signal //thread emitted signal and "executed" by main's slot // unknown number of signal sent (as long as the thread had the CPU?)
main
.
.
.
emitting thread signal //thread emitted signal and "executed" by main's slot
.
.
.
emitting thread signal //thread emitted signal and "executed" by main's slot // unknown number of signal sent (as long as the thread had the CPU?)
main
.
.
.

Talei
27th August 2010, 11:32
Talei what about putting the "emit finThObj( k );" in the for-loop?

With DirectConnection ..., it will CRASH :D See tbscope post for more details.
With QueuedConnection it works fine.

To clarify I never use DirectConnection, I sugested using it because I didn't know (You didn't post it) what exactly You want to achieve. And my reply to tbscope post was simply academic debate and learning opportunity :).

Your QThread subclass is "wrong". Please read this (http://labs.qt.nokia.com/blogs/2010/06/17/youre-doing-it-wrong/) or simply download my example and see how I run code in thread. (don't forget to change connection type to queue :) ).
Also You code in subclassed QThread is "wrong".
Do something like this:


void myThread::run()
{
QTimer::singleShot( 0, this, SLOT(heavyDutyJob()) );
this->exec();
}

void myThread::heavyDutyJob()
{
//do stuf here
this->exit();
}

And the code that I post above is wrong, because You shouldn't use QObject macro in QThread subclass. See the link.

AFAIK manual/qtdocs don't says to subclass QThread ONLY on QTcpSocket class (and they use QTcpSocket as an example there), and that's because QTcpSocket lives in the object it was created in. So to use QTcpSocket in thread You need create it in thread. And the whole commotion around QThread itself is probably because of that.

To sum it up do somethink like this:

QObjec *myWorkingObject = new QObject();
QThread *th = new QThread(); // or QThread th; whaever suits Your needs
myWorkingObject.moveToThread(th);
//.....
connect(....)
th->start();

and use siganl/slots as You want.

And the reason Why You code output was wrong (well output is actually correct) is due to for-loop in MyMainWindow, because that will block Your program (until for loop < 100). And it is exactly what You see in output. 100 x "main" and "signal", 100 x "main" and "signal" ...
Simply Your design is wrong.