Create Thread in QDialog and emit signals to QDialog in Qt - c++

I created an application that has a mainwindow and from this window creates a QDialog. This QDialog should create a RenderThread that emits received images from the camera or in the example emits text. When i debug this it seems that the connection is never made as adding a breakpoint in the slot CameraWindow::debugSomething does not get caught. Whats wrong ?
I followed this example: http://qt-project.org/doc/qt-4.8/threads-mandelbrot.html but it seems that i've done something wrong.
qtDEVC::qtDEVC(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
connect (ui.pushButton_startCam, SIGNAL( clicked() ),this,SLOT( startCam() ) );
/**Threading*/
CameraWindow camWindow = new CameraWindow(this);
}
int qtDEVC::startCam()
{
camWindow.show();
camWindow.startCaptureThread();
}
CameraWindow Class:
CameraWindow::CameraWindow(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
connect(&thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
}
void CameraWindow::debugSomething(std::string something){
QString somethings(something.c_str());
qDebug()<<somethings;
}
int CameraWindow::startCaptureThread(){
RenderThread *thread = new RenderThread(this, guid, CLEYE_COLOR_RAW, CLEYE_VGA, 50);
thread->StartCapture(); //starts thread in low priority and sets _running to true
}
CameraWindow header
class CameraWindow : public QDialog
{
Q_OBJECT
public:
CameraWindow(QWidget *parent = 0);
~CameraWindow();
Ui::CameraWindow ui;
public slots:
int startCaptureThread();
void debugSomething(QString);
private:
RenderThread thread;
};
RenderThread Class
void RenderThread::run()
{
// image capturing loop
while(_running)
{
qDebug()<<("render while()"); //is printed with qdebug correctly
if (restart)
break;
if (abort)
return;
qDebug("it"); //is also printed with qdebug correctly
emit sendText(text);
}
RenderThread header
class RenderThread : public QThread
{
Q_OBJECT
public:
RenderThread(QObject *parent, GUID cameraGUID, CLEyeCameraColorMode mode, CLEyeCameraResolution resolution, float fps);
RenderThread();
~RenderThread();
bool StartCapture();
signals:
void sendText(QString &text);
protected:
void run();
private:
QMutex mutex;
QWaitCondition condition;
//some more private variables for construction
};
I think that this creation seems somehow wrong: RenderThread *thread = new RenderThread(this);

The first thing that's worrying about the question is the word "RenderThread". Note that Qt only allows rendering on the main thread. You can create separate threads for calculations of image data, but whenever you use a painter and draw objects, that must happen on the main thread. However, If you're just going to capture the image and pass that to the main thread, via signals and slots, then that should be ok.
Secondly, whilst you've not shown all your code, I'm assuming from the function called RenderThread::run() and from the Qt example that you may have inherited from QThread here. If this is the case, please note that this is not how to use QThread. Instead, you should have your class inherit from QObject and move that to a QThread. You can read about how to use QThread properly here.
I know it's a Qt example that you've followed, but even the guys at Qt think it's a bad idea. Here's an article of how to really use QThreads.
With that in mind, here's an outline of how I would use QThread for this: -
class CameraWindow : public QDialog
{
private:
CameraObject* m_pCamObject;
};
class CameraObject : public QObject
{
Q_OBJECT
public:
private slots:
startCaptureThread();
private:
};
int CameraWindow::startCaptureThread()
{
m_pCamObject = new CameraObject;
QThread* pThread = new QThread;
this->moveToThread(pThread); // CameraObject will run on the new thread
connect(pThread, SIGNAL(started()), m_pCamObject, SLOT(startCaptureThread()));
connect(pThread, SIGNAL(finished()), pThread, SLOT(deleteLater()); // clear up when
finished
pThread->start();
}
Note that here is a CameraObject, separated from the CameraWindow. The QThread is just a controller of the thread and keeps a clean separation from the CameraObject.
Another reason for handling threads this way is that you can move multiple QObject instances to the new thread, rather than always creating a new thread per object. If you've more threads than CPU cores, you're unlikely to gain by creating yet another thread.

In the constructor of CameraWindow class, you are connecting a RenderThread's signal but it is not the same object which is started in startCaptureThread. Change your startCaptureThread like this:
int CameraWindow::startCaptureThread()
{
thread.StartCapture(); //starts thread in low priority and sets _running to true
}
In this method, the thread member of CameraWindow is started.
P.S.: post the headers too, we can't see the members from this code.

In the mentioned example, CameraWindow class holds a RenderThread thread variable, not a RenderThread *thread.
You are connecting a pointer address in your connect call:
connect(&thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
Try to use a good address:
connect(thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
This is not a tested answer.

Related

Creating QNetworkAccessManager in another thread

I have a QNetworkAccessManager created in another thread.
The network is meant to be used only in MyMegaThread.
QNetworkAccessManager is created from the thread's run method:
mp_manager.reset(new QNetworkAccessManager{this});
On creation I get such a message in console:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is MyMegaThread(0x237eabd0ee0), parent's thread is QThread(0x237e70742a0), current thread is MyMegaThread(0x237eabd0ee0)
This message is totally harmless, but I wonder which parent the manager is supposed to have.
I suspect it happens because the MyMegaThread instance is created in the main thread, but I need a parent created in MyMegaThread instead.
What is an idiomatic way of doing this?
Parent is MyMegaThread(0x237eabd0ee0), parent's thread is
QThread(0x237e70742a0), current thread is MyMegaThread(0x237eabd0ee0)
The issue does not relate to QNetworkAccessManager.
Here is the demo to reproduce the warning.
#include <QDebug>
#include <QThread>
class MyMegaThread : public QThread
{
Q_OBJECT
public:
using QThread::QThread;
protected:
void run() override {
qDebug()<<QThread::currentThread()<<this->thread();
new QObject(this);
}
};
// main
MyMegaThread m;
m.start();
Output:
MyMegaThread(0x60fe18) QThread(0x16a7c48)
It's rule of QObject:
All QObjects must live in the same thread as their parent.
Consequently:
setParent() will fail if the two QObjects involved live in different
threads. When a QObject is moved to another thread, all its children
will be automatically moved too. moveToThread() will fail if the
QObject has a parent. If QObjects are created within QThread::run(),
they cannot become children of the QThread object because the QThread
does not live in the thread that calls QThread::run().
http://doc.qt.io/qt-5/qobject.html#thread-affinity
Have to make sure this code new QObject running QThread be same as given parent QObject thread.
mp_manager.reset(new QNetworkAccessManager{this});
No, the message is not harmless at all. The object you have created has a null parent and no reference on the thread association and thus its thread() method may return a dangling pointer at any time. It cannot safely use timers nor receive cross-thread calls. It is basically as useless object, and you're asking for undefined behavior to strike. This shouldn't be a warning, but a failure. Qt did you a disservice here by allowing you to continue.
The idiomatic way of doing it is first of all not to derive from QThread. QThread is a thread handle. It wraps a system resource. Put all of your functionality into a regular QObject moved into a QThread. The idiomatic way to endlessly "do stuff" on any thread, including the main thread, is to use a zero-duration timer. Note that zero-duration timers have nothing to do with timing at all. They are essentially event loop handles, calling them a timer is a misnomer.
To wit:
// https://github.com/KubaO/stackoverflown/tree/master/questions/thread-simple-50632807
#include <QtNetwork>
class Thread final : public QThread {
Q_OBJECT
public:
void takeObject(QObject *obj) {
obj->moveToThread(this);
}
~Thread() override {
requestInterruption();
quit();
wait();
}
};
class Class : public QObject {
Q_OBJECT
QBasicTimer m_workTimer;
QNetworkAccessManager m_manager{this};
void doWorkChunk() {
qDebug() << "tick...";
QThread::sleep(1); // emulate a blocking operation
}
protected:
void timerEvent(QTimerEvent *ev) override {
if (ev->timerId() != m_workTimer.timerId())
return;
doWorkChunk();
}
public:
explicit Class(QObject *parent = {}) : QObject(parent) {
m_workTimer.start(0, this);
}
};
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
Class object;
Thread workThread;
workThread.start();
workThread.takeObject(&object);
QTimer::singleShot(3000, &QCoreApplication::quit);
return app.exec();
}
#include "main.moc"
The QBasicTimer::stop: Failed. Possibly trying to stop from a different thread warning is relatively benign and indicates an internal timer handle leak. For a workaround, see this answer.

Qt C++ - How to pass data from a worker thread to main thread?

I am trying to perform interthread communication in Qt (C++). I have a worker thread which does some calculations and I want the workerthread to return its results to the main thread when done. I therefor use a connect, I know thanks to debugging, that the signal is successfully being emit but that it is the slot that isn t being executed and I don t understand why.
The relevant pieces of code:
webcamClass::webcamClass(QObject *parent) : QObject(parent)
{
workerThread = new QThread(this);
workerClassObj = new workerClass();
//connect for image
connect(workerClassObj, SIGNAL(mySignal(QPixmap)), this, SLOT(mySlot(QPixmap)));
//connect(&workerClassObj, workerClass::mySignal(QPixmap), this, webcamClass::mySlot(QPixmap));
connect( workerThread, SIGNAL(started()), workerClassObj, SLOT(getImage()) );
workerClassObj->moveToThread(workerThread);
}
void webcamClass:: foo()
{
workerThread->start();
}
void workerClass::getImage()
{
qint64 successFailWrite;
QImage img;
QPixmap pixmap;
... do some stuff with pixmap...
qDebug()<<"going to emit result";
emit mySignal(pixmap);
qDebug()<<"emitted";
}
void webcamClass::mySlot(QPixmap p)
{qDebug()<<"this message should be displayed"; }
The corresponding header files:
class workerClass : public QObject
{
Q_OBJECT
private:
public:
explicit workerClass(QObject *parent = nullptr);
signals:
void mySignal(QPixmap);
};
webcamClass::webcamClass(QObject *parent) : QObject(parent)
{
Q_OBJECT
public:
explicit webcamClass(QObject *parent = nullptr);
public slots:
void mySlot(QPixmap p);
private:
QThread *workerThread;
workerClass *workerClassObj;
};
The code above just outputs:
going to emit result
emitted
but unfortunately doesn t output this message should be displayed.
webcamClass belongs to the parent thread, while workerClass belngs to -you guessed it- the worker thread.
Could someone explain how to setup my connect so that mySlot() gets triggered?
Thanks!
In the code you pasted in pastebin.com/UpPfrNEt you have a getVideoFrame method that uses while (1). If this method is called, it runs all the time and blocks the event loop from handling signals. You can solve it in many ways, I think the best practice will be to replace the while(1) with something else.
If possible, I highly encourage you to use the new Signal Slot syntax:
connect( SOURCEINSTANCE, &CLASS::SIGNAL, TARGETINSTANCE, &CLASS::SLOT );
In your case, that could be:
connect( workerClassObj, &workerClass::mySignal, this, &webcamClass::mySlot );
Specificallyfor your case, if you want to pass Signals and Slots between threads, you have to be careful. First, check the connection type for the connect call, its acutally the last parameter.
connect( workerClassObj, &workerClass::mySignal, this, &webcamClass::mySlot, Qt::QueuedConnection );
For a detailed explanation look here:
http://doc.qt.io/qt-5/signalsandslots.html
If you want to pass custom types, you have to declare them as metatypes first.
Add e.G. this in your constructor:
qRegisterMetaType("MyDataType");
Please make sure, that your custom datatype has a default constructor and be aware that afaik, references cannot be passed across threads.

signal and slot in QT

i have a problem in working signal and slot in QT framework .
my slot is not working .
here is the code .
connect(&th,SIGNAL(change()),this,SLOT(closeWindow()));
this->moveToThread(th);
closeWindow();
th.start();
"th" is a var from a class like this :
class Thread : public QThread
{
public :
Thread();
bool pause,flag;
QString URL;
QFile *mFile;
void run();
void RESUME();
void PAUSE();
bool Check();
bool Check2();
signals:
void change();
QString myTxt;
};
"change" is the signal
and here is the code of my MainWindow :
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
Thread th;
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
public slots:
void closeWindow();
};
and here is the constructor for MainWindow
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&th,SIGNAL(change()),this,SLOT(closeWindow()));
th.start();
}
the signal is Ok . but the Slot is not Working .
can You guide me ?
I think the main issue is that the receiving object lives in a dead thread.
Your Thread instance lives on the application thread, while your MainWindow lives on the thread created by your Thread instance. However as you have reimplemented QThread::run(), you do not have an event loop on this thread and the slot can never be invoked.
Check Qt documentation for details:
Threading Basics
Threads and QObjects
Also you have some big issues in your code:
Missing Q_OBJECT macro in Thread definition (but you might have removed it while copy/pasting otherwise you wouldn't be able to emit the signal).
You must not call moveToThread() on object derived from QWidget (e.g QMainWindow). QWidgets must live on the application thread.
You generally cannot mix using moveToThread() and reimplementing run().
When using moveToThread() you are using the thread event loop to make QObjects living on this thread (i.e moved to this thread) live.
When reimplementing QThread::run(), people generally want to execute a single function on a thread. This will lead to a thread being created, the function executed and the thread destroyed without running an event loop. And no event loop mean that if a QObject lives on this thread, it will not received inter-thread slot invokations.
NB: Using moveToThread() is the correct/intended way to use QThread. Reimplementing QThread::run() will work and can be found in Qt documentation but isn't generally recommended and you might be better of using QThreadPool.
More readings: http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/

How to thread a QGLWidget?

I have widget:
class Main_Widget : public QWidget
{
Q_OBJECT
public:
explicit Main_Widget(QWidget *parent = 0);
~Main_Widget();
private:
MyOGLWidget *mOGL;
QThread *mThread;
QPushButton *mStart;
QPushButton *mStop;
}
Then, I created all as following:
mOGL = new MyOGLWidget();
mThread = new QThread();
mStart = new QPushButton();
mStop = new QPushButton();
//move to other thread
mOGL->moveToThread(mThread);
I want to use animation at the mOGL. For this idea, I have a following code:
class MyOGLWindow : public QGLWidget
{
private:
bool mEnd; //default false
//...
public:
void doLoop()
{
while(mEnd)
{
//animation
updateGL();
}
}
public slots:
void slotStart()
{
mEnd = true;
}
void slotStop()
{
mEnd = false;
}
}
And I do connect my two buttons to slotStart(), slotStop(). But If I use start button(which causes slotStart()), my Main_Widget is freezes, but my animation is successfully works. How I can start my infinity loop and not to freeze my Main_Window, and how to stop?
The UI, other than the OpenGL view, freezes since you don't return to the event loop. It is an error to move any class that derives from QWidget, including QGLWidget, to another thread.
To do rendering from another thread, you need to move the QGLContext (and not QGLWidget) to the render thread. Follow the documentation of QGLWidget in this respect. The widget's paint event handler must do nothing - since otherwise it would use the GL context from the wrong (GUI) thread. You can use a zero-duration timer in a QObject running in the render thread to obviate the need for a custom end flag. Whenever the thread's event loop is finished by invoking QThread::quit(), the object will stop executing.
You also need to use a thread class that's safe to destruct. Properly designed C++ classes are always destructible. QThread is a weirdo - we fix it here.
As a matter of style, it is not necessary to have widget children allocated on the heap. It's a minor waste of heap, in fact, since heap blocks have overhead comparable to the size of a QObject instance.
The below shows a sketch of things that need to be addressed for multi-threaded OpenGL in Qt.
class Thread : public QThread {
using QThread::run; // final
public:
~QThread() { quit(); wait(); }
};
class ThreadGLWidget : public QGLWidget
{
void paintEvent(QPaintEvent *) {}
void resizeEvent(QResizeEvent *) { emit resized(size()); }
public:
explicit ThreadGLWidget(QWidget * parent = 0) : QGLWidget(parent) {
// Release the context in this thread.
doneCurrent();
}
Q_SIGNAL void resized(QSize);
};
class Animator : public QObject
{
Q_OBJECT
QBasicTimer mTimer;
QSize mWidgetSize;
QPointer<QGLContext> mGLContext;
void nextFrame() {
mGLContext.makeCurrent();
...
updateGL();
}
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() == mTimer.timerId()) nextFrame();
}
public:
explicit Animator(QGLContext * ctx, QObject * parent = 0) :
QObject(parent), mGLContext(ctx)
{
// The use of the timer obviates the custom stop flag. Our
// thread's event loop is not blocked and is quittable.
mTimer.start(0, this);
}
Q_SLOT void setSize(QSize size) { mWidgetSize = size; }
};
class Main_Widget : public QWidget
{
Q_OBJECT
public:
explicit Main_Widget(QWidget *parent = 0) : QWidget(parent),
mLayout(this), mStart("Start"), mStop("Stop"),
mAnimator(mOGL.context())
{
mLayout.addWidget(&mOGL, 0, 0, 1, 2);
mLayout.addWidget(&mOGL, 1, 0);
mLayout.addWidget(&mOGL, 1, 1);
mAnimator.setSize(mOGL.size());
mOGL.context()->moveToThread(&mThread);
mAnimator.moveToThread(&mThread);
mAnimator.connect(&mOGL, SIGNAL(resized(QSize)), SLOT(setSize(QSize)));
mThread.start();
}
private:
QGridLayout mLayout;
ThreadGLWidget mOGL;
QPushButton mStart;
QPushButton mStop;
Animator mAnimator; // must be declared before its thread and after the GL widget
QThread mThread;
// Destruction order of GL-related objects:
// 1. mThread - stops the animation, makes the animator and context threadless
// 2. mAnimator - now threadless, can be destructed from our thread
// 3. mOGL - its context is threadless and can be destructed from our thread
}
The proper way to handle animation on a QGLWidget is to use a QTimer, not a QThread!
Overwrite QGLWidget's initialization method, initializeGL(), to start the timer. You can use something like this, which calls _tick() every 33ms:
QTimer::singleShot(33, this, SLOT(_tick()));
I just want to clarify that singleShot() is a static method of QTimer, which fires only once. That means that when _tick() (private slot) is called, it should do a few things:
Update all the variables that control animation (rotation, movement, speed, etc);
Trigger paintGL() indirectly, by calling updateGL();
Start a new singleShot timer.
void GLWidget::_tick()
{
/* 1- Update state variables */
/* 2- Call paintGL() indirectly to do the drawing */
updateGL();
/* 3- Set a new singleShot timer to invoke this method again, 33ms from now */
QTimer::singleShot(33, this, SLOT(_tick()));
}
That's how you should handle animation with QGLWidget.
All GUI operations must run in one thread.
http://qt-project.org/doc/qt-4.8/thread-basics.html#gui-thread-and-worker-thread
GUI Thread and Worker Thread
As mentioned, each program has one thread when it is started. This
thread is called the "main thread" (also known as the "GUI thread" in
Qt applications). The Qt GUI must run in this thread. All widgets and
several related classes, for example QPixmap, don't work in secondary
threads. A secondary thread is commonly referred to as a "worker
thread" because it is used to offload processing work from the main
thread.
This is also true in Qt 5,
http://qt-project.org/doc/qt-5/thread-basics.html#gui-thread-and-worker-thread

Using QThread and moveToThread properly with QTimer and QTcpSocket

From reading this blog, this blog and some others, Subclassing QThread is bad practice. So I tried to apply this method.
But my problem is that I have a QTimer and a QTcpSocket in the class I want to move to a different thread. Suddenly, it's not as easy as it the examples used. :(
QThread m_commsThread;
m_pICommsHandler = new CommsHandlerIP();
m_pICommsHandler->moveToThread(&m_commsThread);
m_commsThread.start();
And here is the CommsHandlerIP class, methods are not included.
class CommsHandlerIP : public QObject
{
Q_OBJECT
public:
CommsHandlerIP();
~CommsHandlerIP(void);
protected:
QTcpSocket m_TCPSocket;
QTimer m_timer;
}
Issue is that the QTimer and the QTcpSocket (inside CommsHandlerIP class) are in the main thread even if you move CommsHandlerIP. So I can't start the timer or connect the socket.
If I try to moveToThread the QTimer and QTcpSocket (inside the constructor by passing the thread pointer for instance), this become really messy when I leave the app.
What should I do?
Class Instances are created on the calling thread.
QTimer inherits QObject.
Each Thread on Qt can have an event loop if it calls exec().
so you want to move QTimer to an event loop on another thread.
so you should manually move it.
Therefore, delay their creation until after you move the object: -
class CommsHandlerIP : public QObject
{
Q_OBJECT
public slots:
void Initialise();
private:
void Run();
// c++ 11, initialising in headers...
QTimer* m_pTimer = NULL;
QTcpSocket* m_pSocket = NULL;
};
void CommsHandlerIP::Initialise()
{
m_pTimer = new QTimer(this);
m_pSocket = new QTcpSocket(this);
Run();
}
QThread m_commsThread;
m_pICommsHandler = new CommsHandlerIP();
// Note Qt 5 connect style
connect(&m_commsThread, &QThread::started, m_pICommsHandler, &CommsHandlerIP::Initialise);
m_pICommsHandler->moveToThread(&m_commsThread);
m_commsThread.start();
When the thread is started, the CommsHanderIP Initialise function is called; this is where you should create and setup the QTcpSocket and QTimer objects before calling Run(). As the CommsHandlerIP is running in the new thread before creating those objects, they will also share the same thread affinity.
There is a much simpler method of achieving all this that follows the same algorithm but doesn't involve all the boilerplating needed to create threads and changing thread affinities, using QRunnable and QThreadPool
If I convert Merlin069's example, you'll see how it simplifies the code a bit:
class CommsHandlerIP : public QObject, public QRunnable
{
Q_OBJECT
public:
void run();
public slots:
//... any slots
signals:
//... any signals
private:
// c++ 11, initialising in headers...
QTimer* m_pTimer = NULL;
QTcpSocket* m_pSocket = NULL;
};
void CommsHandlerIP::run()
{
m_pTimer = new QTimer();
m_pSocket = new QTcpSocket();
//...
delete m_pTimer;
delete m_pSocket;
}
QThreadPool::globalInstance()->start(new CommsHandlerIP);
I stumbled across this when searching on Timer behaviour and movetoThread.
The accepted answer is a good work-around but not really the root cause of the problem. There is a general rule that when you move an object then all child objects will move as well. So you just need to make sure that the QTimer becomes a child so pass the this pointer in its constructor.
CommsHandlerIPL::CommsHandlerIP()
: QObject(), m_pTimer(new QTimer(this)) // <=== crucial to make it a "child" object
{
}