You are not logged in.

Dear visitor, welcome to QtForum.org. If this is your first visit here, please read the Help. It explains in detail how this page works. To use all features of this page, you should consider registering. Please use the registration form, to register here or read more information about the registration process. If you are already registered, please login here.

1

Friday, June 1st 2012, 5:39am

Signals and slots across threads

Hi

I read tonnes of online information about Qt threading, so here i am trying to follow the most correct standard way of Qt threading, but i ended up just couldn't get my signal and slot connected across threads! I have read and accept that not to derive my class from QThread to do heavy processing work,( see this, http://qt-project.org/wiki/Threads_Events_QObjects) and http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/

as it is wrong and not recommended in new Qt.



I put my cpp codes into the header declaration here to save some typing., but you understand what i am trying to achieve.

Here are my codes:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class DLLEXPORT Worker: public QObject
{
		Q_OBJECT

   Worker()
  {
      	
   QObject::connect(&_timer,SIGNAL(timeout()),this,SLOT(doWork()));
   long id=(long)QThread::currentThreadId();
}
	~Worker();

signals:
	void Changed(const Data&);

public slots:
	void start()
{
//the program does reach here

	_timer.start(1000);
}
	void doWork()
{
//The problem is this never get called!! Even though i have started the timer in start() func above
}
	void stop()
{
//this is called when i clicked my UI push button
}

private:
	QTimer _timer;

};


In a separate GUI application:

qmain::qmain(QWidget *parent, Qt::WFlags flags)
	: QMainWindow(parent, flags)
{
	ui.setupUi(this);
	

	QThread  *pThread= new QThread;
	Worker*worker= new Worker;
	
	QObject::connect(ui.pushButton, SIGNAL(clicked()),worker, SLOT(stop()));
	worker->connect(pThread,SIGNAL(started()),SLOT(start()));	

	worker->moveToThread(pThread); //Everything works if i commented out this line. But i guess this is not what i want, as i want the doWork to be done in separate thread.

	pThread->start();
	

	long id=(long)QThread::currentThreadId();

}

This post has been edited 1 times, last edit by "mce" (Jun 1st 2012, 5:45am)


2

Friday, June 1st 2012, 8:41am

qtimer might have problems cross-thread.

you need to be careful because it is created in main thread, and it WONT be moved when you move worker to other thread because qtimer in worker does NOT have worker as parent.

Why do you have to timer anyway? Remove the timer and do this:

Source code

1
2
3
4
5
6
worker->moveToThread(pThread);

QObject::connect(ui.pushButton, SIGNAL(clicked()),worker, SLOT(stop()));
worker->connect(pThread,SIGNAL(started()),SLOT(start()));	

pThread->start();


and call doWork directly from worker::start()
If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

3

Friday, June 1st 2012, 3:03pm

I need to run doWork for as long as my application is running, are you suggesting the following? If so, this is not the recommended way according to http://qt-project.org/wiki/Threads_Events_QObjects, this document seems to propose to use a timer for what i want to achieve, if i understand correctly.

Also, doing it this way, i am having problem to get the stop() called when i clicked the ui push button, which i connect them together in my qmain, as shown in my origianl post. How to have stop() slot in worker being correctly connected to ui.pushbutton clicked signal??

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public slots: 
void start() 
{ 
while(!stop) 
{ 
doWork(); 
SleepThread::msleep(2000); 
} 
} 

void doWork() 
{ 
..... 
} 

//the following doesn't get invoked when ui pushbutton is clicked.
void stop() 
{ 
stop=true; 
//this should be called when i clicked my UI push button 
}

4

Friday, June 1st 2012, 5:49pm

no, I'm not saying that. I momentarily mixed up behaviour of timer with singleshot.
If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

5

Friday, June 1st 2012, 5:52pm

what you have is verbatim code from another source so I'm surprised it doesn't work. Have you double checked that there are no debug messages output to the console?
If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

6

Friday, June 1st 2012, 6:05pm

just tried your code and I get this message:


QObject::startTimer: timers cannot be started from another thread


It helps to pay attention ;) I was right with my first post to be suspicious of that QTimer being created in one thread but used in another.



Here is the fix:

Source code

1
2
3
4
5
Worker::Worker() :
    _timer(this)
{
    QObject::connect(&_timer,SIGNAL(timeout()),this,SLOT(doWork()));
}
If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

7

Tuesday, July 3rd 2012, 9:04am

I am revisiting the codes and i found something which i do not understand

Inside the Worker class start method, i tried to check the thread affinity of timer as follow:

Source code

1
2
3
4
5
6
7
void start()
{

//the program does reach here

    _timer.start(1000);
}

8

Tuesday, July 3rd 2012, 9:11am

I am revisiting the codes and i found something which i do not understand

Inside the Worker class start method, i tried to check the thread affinity of timer as follow: Both id1 and id2 are the same (worker's thread id) regardless whether i initialize _timer in worker class with "this" or not. I suppose if i do not pass "this" to the _timer during initialization, i should get the main thread id when i tried to check on its affinity? , as you said, _timer doesn't move to worker's thread even though i tried to moveToThread(workerThread) in the main thread, if i don't initialize timer with "this" as parent.

Just found out about the following:
"
The function in question returns the id of the currently executing thread, and not the thread affinity of the object that you're trying to call it on.
If you want to get a reference to the thread object that the object has affinity for, use QObject::thread() instead.
"

I am wondering how to achieve this? how to know two different thread id??

Source code

1
2
_timer.thread()?
QThread::thread()??


Source code

1
2
Worker::Worker() : _timer(/*this*/) 
{ QObject::connect(&_timer,SIGNAL(timeout()),this,SLOT(doWork())); }






Source code

1
2
3
4
5
6
7
8
9
10
void start() 
{ 

//id1 and id2 always the same regardless _timer initialization with "this" or not 
long id1=(long)_timer.thread()->currentThreadId(); 
long id2=(long)QThread::currentThreadId(); 
//the program does reach here 

_timer.start(1000); 
}

This post has been edited 2 times, last edit by "mce" (Jul 3rd 2012, 10:08am)


9

Tuesday, July 3rd 2012, 12:35pm

If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.