PDA

View Full Version : QMessageBox.exec() does not block Producer-Consumer signal loop



airproject
30th August 2012, 11:20
Hi!,
I have a singlethreaded application which performs some longer task. The task is devided in to small portions and accomplished by Producer-Consumer, Qt::QueuedConnection, signal-slot loop. Everthing works well, gui is responsive.
I have a 'Stop' button in the gui. In its 'onClick' event handler i am displaying a confirmation message with use of QMessageBox::exec() function.

Unfortunately i am facing the following problem:
When the confirmation message is displayed, sometimes the Producer-Consumer loop is blocked and sometimes it proceeds unaffected.
I would like the modal confirmation box to block the execution of the Producer-Consumer loop.

I have read that exec() runs its own event loop and this would explain why Producer-Consumer loop proceeds. However, i am confused with the fact that sometimes it is blocked. And still.. i would like to block this loop somehow.

Any ideas?
best regards.

amleto
30th August 2012, 12:50
exec() makes another event loop - but you can think of this as another version of the gui event loop.

I dont think it will be interfering with the running of other threads, and I think it should not be halting the execution of slots in the gui thread.

If you want to be able to block your producer/consumer, I suggest looking at something like this:


void
myclass::slot_block()
{
QEventLoop eventLoop;
connect(this, SIGNAL(continue()), &eventLoop, SLOT(quit()));
eventLoop.exec(); // will process signals/slots, but myclass
// will not otherwise execute any more code until the loop is exited
}

void
myclass::slot_continue()
{
emit continue();
}

ie you need to implement two slots and a signal.

airproject
30th August 2012, 16:17
Thank you for the reply.
If i understand you well:
- QMessageBox::exec() - executes an event loop which processes the GUI thread signals (processes Producer-Consumer, filters out only widget signals?)
- creating new QEventLoop and running it will be processing utterly new event loop separated form GUI thred with Producer-Consumer signals. This loop will engage application processing untill i quit() it.

I guess Displaying QMessageBox should be accomplished with some other method (open(), show()) than exec().

I will do some trials.. and still wonder why sometimes the GUI thread event loop is blocked by exec() and sometimes no:/

Best regards.

airproject
30th August 2012, 19:23
Thanks to amleto I have identified reason why the Consumer-Producer loop soemtimes is blocked by QMessageBox::exec().

In the Consumer method i have used the following pattern to synchronize asynchronous operation:

QNetworkAccessManager manager;
QEventLoop q;
QTimer tT;

tT.setSingleShot(true);
connect(&tT, SIGNAL(timeout()), &q, SLOT(quit()));
connect(&manager, SIGNAL(finished(QNetworkReply*)),
&q, SLOT(quit()));
QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("http://www.qtcentre.org")));

tT.start(5000); // 5s timeout
q.exec();

if(tT.isActive()){
// download complete
tT.stop();
} else {
// timeout
}

- If the 'Stop' button is pressed and its OnClick method containing QMessageBox::exec() is executed when Consumer is at q.exec() line , the appliction stops execution at q.exec() line untill the QMessagBox dialog is closed.
- Contrary, if the Stop' button is pressed, and its OnClick method containing QMessageBox::exec() is executed before or after Consumer q.exec() line, then Consumer-Producer loop continues to work.

It looks like neither
connect(&tT, SIGNAL(timeout()), &q, SLOT(quit()));
nor
connect(&manager, SIGNAL(finished(QNetworkReply*)),
signal can reach its slot and finish q.exec() event loop when QMessageBox::exec() is executed. It looks like what amleto proposed with exception that the QMessageBox::exec() is blocking q.exec() event loop.

How could i make the application running, and not lock on q.exec()?

Added after 18 minutes:

Problem solved.
1. The Producer-Consumer signal loop was blocked by the QEventLoop q.exec() which could not be finished due to QMessagBox which was exec()uted while q.exec() was running. When event loop is running it cannot be interrupted by QMessageBox.exec:
"Generally speaking, no user interaction can take place before calling exec(). As a special case, modal widgets like QMessageBox can be used before calling exec(), because modal widgets use their own local event loop."http://qt-project.org/doc/qt-4.8/qeventloop.html#exec

2. To avoid locking of EventLoop by some messages which are displayed in GUI slots, it is enough to exec()ute the event loop with parameter QEventLoop::ExcludeUserInputEvents:
"Do not process user input events, such as ButtonPress and KeyPress. Note that the events are not discarded; they will be delivered the next time processEvents() is called without the ExcludeUserInputEvents flag."http://qt-project.org/doc/qt-4.8/qeventloop.html#ProcessEventsFlag-enum

3. If someone wants to block totaly all events in the GUI thread when the QMessageBox is exec()uted, try amaleto solution with additional QEventLoop.

Thanks.

amleto
30th August 2012, 23:28
thanks for investigation & feedback :)