PDA

View Full Version : Update GUI from another object with 2 threads.



jiapei100
17th February 2013, 15:31
Hi, all:

I’ve got a class which has a producer thread and a consumer thread. I would like the producer thread keeps producing the image data, and whenever the consumer thread is consuming the image data from the shared buffer, a signal will be sent out to the MainWindow GUI, for the purpose of redraw the image on GUI —- this signal/slot is of Qt::BlockingQueuedConnection for sure.

However, I’ve got no idea why this doesn’t work for me now (no image has ever been drawn on the MainWindow GUI). I guess it’s probably because, the signal sent out to the MainWindow GUI is embedded inside the critical section — the consumer thread lock the critical shared buffer using a mutex, and I sent out the signal from within this locked mutex section to the MainWindow GUI. Is this problematic? And is there a way out for my issue?

Cheers
Pei

anda_skoa
17th February 2013, 19:53
Any specific reason why you are using a BlockingQueuedConnection and not a normal QueuedConnection (or simply AutoConnection which results in a QueuedConnection when being used across thread boundaries)?

Are you transporting the image as a signal argument?

Cheers,
_

jiapei100
18th February 2013, 04:03
Hi, anda_skoa:

Thank you for your prompt reply... Yes. I am transport the image as a signal argument , and I'm using Qt::BlockingQueuedConnection.
If I use Qt::DirectConnection, I always get the following error message, and nothing has been drawed on the MainWindow:

QPixmap: It is not safe to use pixmaps outside the GUI thread

Now, I changed my signal/slot now, and avoid using the image as a signal argument. And, I'm trying to use Qt::QueuedConnection as suggested by you, it seems all signals emitted by my code are queued there forever, and nothing has ever been drawn on GUI... During debugging, whenever I paused the program, the debugging pointer will point to the line this->m_threadGroup.join_all(); . the code patch is attached



void LVStream::start()
{
this->m_threadProducer = boost::thread(&LVStream::producer, this);
this->m_threadConsumer = boost::thread(&LVStream::consumer, this);
this->m_threadGroup.add_thread(&this->m_threadProducer);
this->m_threadGroup.add_thread(&this->m_threadConsumer);
this->m_threadGroup.join_all();
}




Any further suggestions please?
Thank you very much.


Pei




Any specific reason why you are using a BlockingQueuedConnection and not a normal QueuedConnection (or simply AutoConnection which results in a QueuedConnection when being used across thread boundaries)?

Are you transporting the image as a signal argument?

Cheers,
_

jiapei100
18th February 2013, 08:10
Hi, anda_skoa:

I now packaged my code as a .tar.gz file at http://visionopen.com/questions/QtThreadExample.tar.gz . Please have a look at it, and help to let me know what's wrong with my code. I do need your help.


Best Regards
Pei

wysota
18th February 2013, 10:50
Your are blocking the main thread (by calling m_threadGroup.join_all()) so it won't update anything. You should join the threads when they are done with their work. If you use QThread instead of boost threads, you will get a notification when a thread exits.

jiapei100
18th February 2013, 11:25
Hi, wysota:

Thank you so much for your reply... Yes, the symptom is just my own boost::thread_group (with 2 boost::thread, one consumer, one producer) blocked the main thread.
join the threads when done with their work? What I would like to realize is:

1) producer thread is a boost::thread
2) consumer thread is also a boost::thread
3) whenever consumer thread successfully retrieved some data from the buffer, consumer thread will emit a signal and a MainWindow slot will respond this emit and update Qt GUI MainWindow .


Is it possible to realize this?? If so, how to?

Cheers
Pei







Your are blocking the main thread (by calling m_threadGroup.join_all()) so it won't update anything. You should join the threads when they are done with their work. If you use QThread instead of boost threads, you will get a notification when a thread exits.

wysota
18th February 2013, 11:37
There are many examples showing how to do that with Qt. But you can't block the main thread if you want it to do something in the meantime. Start the threads and return from the function call. When threads are done with their work, end them.

jiapei100
18th February 2013, 14:15
Hi, wysota:


Thank you so much... I finally understand what you are talking about. I removed join() and boost::thread_group . Now, it's working again. ^_^

Thank you so much.

Pei




There are many examples showing how to do that with Qt. But you can't block the main thread if you want it to do something in the meantime. Start the threads and return from the function call. When threads are done with their work, end them.

anda_skoa
19th February 2013, 18:27
I see this is already solved, but some additional info anyway:



Thank you for your prompt reply... Yes. I am transport the image as a signal argument , and I'm using Qt::BlockingQueuedConnection.
If I use Qt::DirectConnection, I always get the following error message, and nothing has been drawed on the MainWindow:

Yes, a DirectConnection is a direct method call so the slot will be executed by the emitting thread. We have QueuedConnection for that. Which is the chosen automatically if you don't pass a connection type argument, i.e. when the connection type defaults to AutoConnection.



Now, I changed my signal/slot now, and avoid using the image as a signal argument.

Actually I would recommend passing the image as a signal argument, this way you don't have to access any worker thread members from the GUI thread.



And, I'm trying to use Qt::QueuedConnection as suggested by you, it seems all signals emitted by my code are queued there forever, and nothing has ever been drawn on GUI... During debugging, whenever I paused the program, the debugging pointer will point to the line this->m_threadGroup.join_all(); . the code patch is attached


As you have already found out the problem was that you blocked the GUI thread. Cross-Thread Signal/Slot connections (Queued and BlockingQueued) need to have a running event loop on the receiver thread.

This is because the way QueuedConnection works is to create a slot invocaton event, store all signal arguments in it and then send it to the receiver object's thread. So that thread needs to be processing events to actually perform the slot call.

Cheers,
_