[solved] Queued Signals
-
Hi
I wrote a program that Share a QString between 2 threads using signal/slot and in the slot I just print the Qstring. the problem is when I run the program, nothing displayed until the threads stop working and then all of the prints display immediately.
is that a problem or that is the way Queued Signals work?
-
Are you printing using printf()? Then this is normal and has nothing to do with QueuedConnections. Use qDebug() or cerr instead.
-
Ok, then there can be a lot of issues. Let's move go through a checklist :)
Is this a console application?
Is the sending thread busy (does it have a chance to enter the event loop)?
Is the receiving thread busy (does it have a chance to enter the event loop)?
-
-
yes
-
in it's run method there's a while loop that keep emitting writeText signals... is that called "busy"?
3.recivieng thread is just a simple thread that call exec() in run method and call quit in a slot that I wrote for it called stop. and has another slot called write that is in charge of printing texts...
-
-
It may be that you are not giving the meta object system a chance to send your signals.
In GUI applications, everything revolves around the even loop, so QueuedConnections ususally work without any problems, because every time a function ends, the event loop kicks in and processes all signals.
In console applications, the flow is often much more linear and "packed" with things to do. There are many ways to make it work for you, but we will start small.
First, I suggest reding "the documentation":http://qt-project.org/doc/qt-5/qthread.html, because it looks like you have subclassed QThread, which is not needed/ recommended in most cases.
Second. Try adding this line after you emit the signal:
@
QCoreApplication::instance()->processEvents();
@
it will work through the queue in the event loop and process all signals. If that does not "unblock" your printing, then the problem lies on the other side (the thread).Please note that in many cases calling processEvents() can lead to unexpected results, so I recommend using it with care. Here I mention it because it should allow us to quickly determine the cause of your problem.
-
OK, so it may be that the receiving thread is blocking here. Add the same line there, somewhere in your loop inside run() function.
... oh wait, it may be that you don't have any loop in your thread, just exec(). If yes, then please remove it and see what happens. I do recommend doing it without subclassing, yes, it is usually simpler, creates nicer code, and is easier to understand.
-
Hi,
It could also be that your output stream is not flushed. Where do you print the messages to? (The console? Or Qt Creator's application output pane? Or Somewhere else?)
Anyway, could you please post your code? That makes it much easier to find the issue.
-
removing exec() and add thath line in receiving thread didn't wotk either! here is my code :
@#ifndef TEXTANDNUMBER_H
#define TEXTANDNUMBER_H#include <QtCore>
class TextAndNumber
{
public:
TextAndNumber();
TextAndNumber(int, QString);int number; QString text;
};
Q_DECLARE_METATYPE(TextAndNumber);
#endif // TEXTANDNUMBER_H
@
@#include "textandnumber.h"TextAndNumber::TextAndNumber()
{
}TextAndNumber::TextAndNumber(int num, QString txt)
{
number = num;
text = txt;
}
@
@#ifndef TEXTDEVICE_H
#define TEXTDEVICE_H#include <QThread>
#include "textandnumber.h"class TextDevice : public QThread
{
Q_OBJECTpublic:
TextDevice();
void run();
void stop();public slots:
void write(TextAndNumber tan);private:
int count;
};#endif // TEXTDEVICE_H
@
@#include "textdevice.h"
#include <QtCore>TextDevice::TextDevice() : QThread()
{
count = 0;
}void TextDevice::run()
{
exec();void TextDevice::stop()
{
quit();
}void TextDevice::write(TextAndNumber tan)
{
qDebug() << QString("Call %1 (%3) : %2").arg(tan.number).arg(tan.text).arg(count++);
}
@
@#ifndef TEXTTHREAD_H
#define TEXTTHREAD_H#include <QThread>
#include <QDebug>
#include "textdevice.h"class TextThread : public QThread
{
Q_OBJECTpublic:
TextThread(const QString &text);
void run();
void stop();signals:
void writeText(TextAndNumber);private:
QString m_text;
bool m_stop;
int m_count;
};#endif // TEXTTHREAD_H
@
@#include "textthread.h"TextThread::TextThread(const QString &text) : QThread()
{
m_text = text;
m_stop = false;
m_count = 0;
}void TextThread::run()
{
while(!m_stop)
{
emit writeText(TextAndNumber(m_count++, m_text));
sleep(1);}
}
void TextThread::stop()
{
m_stop = true;
}@
@#include <QCoreApplication>
#include "textthread.h"
#include "textandnumber.h"
#include <iostream>
#include <QtCore>int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);qRegisterMetaType<TextAndNumber> ("TextAndNumber"); TextDevice device; TextThread foo( "Foo" ), bar( "Bar" ); QObject::connect( &foo, SIGNAL(writeText(TextAndNumber)), &device, SLOT(write(TextAndNumber))); QObject::connect( &bar, SIGNAL(writeText(TextAndNumber)), &device, SLOT(write(TextAndNumber))); foo.start(); bar.start(); device.start(); char ch; std::cin >> ch; foo.stop(); bar.stop(); device.stop(); foo.wait(); bar.wait(); device.wait(); return a.exec();
}
@ -
Well, there are some issues with this code.
First, I recommend explicitly adding Qt::QueuedConnection to both of your connect statements.Second, please consider this quote from the documentation:
[quote]It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.[/quote]Third. TextThread::stop() is changing m_stop variable while run() is using it - dangerous.
-
Great, good to hear that! I have marked the thread as solved. Happy coding :-)