i've created a thread in QT using QThread but the parent of the thread is exiting before the thread finishes which itself is running infifnitely.
//mainwindow.cpp
void MainWindow::showEvent(QShowEvent *ev)
{
QMainWindow::showEvent(ev);
showEventHelper();
}
void MainWindow::showEventHelper()
{
//back-end thread
ServerStart *serverstart = new ServerStart();//initializing a pointer to my class
QThread thread;
serverstart->moveToThread(&thread);
QObject::connect(&thread, &QThread::started, serverstart, &ServerStart::run);
thread.start();
//in std::thread i used to detache it like so:
//std::thread worker(serverMain);
//worker.detach();
}
IMPORTANT: I'm making a GUI project. and my infinite thread is inside an onShow() method that needs to exit in order for the app to continue and make the UI. and I also want to send signals in the future from the thread to the main thread and the main thread should be able to respond and modify the UI according to the signal.
how can i do the same in QT?
You can't, however according to KDAB documentation of proper QThread usage you can emulate such behavior by connecting QThread::finished to QThead::deleteLater as shown from their document for QThread here https://www.kdab.com/wp-content/uploads/stories/multithreading-with-qt-1.pdf
Related
I'm using QThread's event loop to communicate with worker threads.
I noticed that I can't use the thread's event loop just after a start.
The following code does not work, as threadEventDispatcher appears to be NULL.
QThread *thread = new QThread;
thread->start();
auto* threadEventDispatcher = thread->eventDispatcher();
Q_ASSERT(threadEventDispatcher != nullptr);
QMetaObject::invokeMethod(threadEventDispatcher, [] { printf("Hello world\n");
According to Qt doc,
An event dispatcher is automatically created for the main thread when QCoreApplication is instantiated and on start() for auxiliary threads.
By browsing the QThread source code, I'm under the impression that the eventDispatcher is created in the running thread, which may not yet be ready when start exits.
I managed to access the eventDispatcher by using a sleep after the start, but I could not find an API that would allow me to properly wait for the thread to actually run.
How can I wait for the thread to actually run, and access eventDispatcher ?
Simply connect to QThread::started() signal.
I have a Qt GUI application which contains some classes and a main. For one of the computationally heavy writing operation i created a a QThreadas a class member. Something like this:
//class members
std::unique_ptr<QThread> m_savingThread;
std::unique_ptr<DiffClass> m_controller;
connect(this, &SomeClass::saveAll, m_controller.get(), &DiffClass::saveToAll, Qt::QueuedConnection);
connect(m_controller.get(), &DiffClass::done, m_savingThread.get(), &QThread::quit);
void SomeClass::saveToFile()
{
//Saving thread
qDebug() << "From main thread:" << QThread::currentThreadId();
m_controller->moveToThread(m_savingThread.get());
m_savingThread->start();
qRegisterMetaType<std::string>("std::string");
emit saveAll(someString);
}
The above code works fine. But i need the m_controller object back to the main GUI thread once the saving operation is finished. I could find something similar
here. Briefly, it states that since QThread can only "push" the object into a thread, i need to push it again into the main thread from the current worker thread.
void DiffClass::saveToAll(someString)
{
qDebug() << "From worker thread:" << QThread::currentThreadId();
/*saving operation*/
moveToThread(QApplication::instance()->thread()); //Error QCoreApplication has no member thread()
emit done();
}
Is there a way to change the affinity of the object back to the main thread?
EDIT 1: My connect to saveToAll is a QueuedConnection.
First and foremost, why would you want to switch thread affinity back and forth? There doesn't seem to be a practical side to this.
Other than that, it should be possible to change it to another threat, the condition is that the object has no parent and the moveToThread() is invoked from the current affinity thread.
You can use QMetaObject::invokeMethod() with Qt::QueuedConnection specified from any thread to schedule a slot execution from the current affinity thread, which will change affinity from the right thread to whatever thread you pass as a parameter.
But seeing how you try to change it from inside the class, that should work as expected, as long as saveToAll() is invoked via the signal/slot mechanism (rather than directly from just about any thread).
//Error QCoreApplication has no member thread()
It most certainly does according to the documentation.
Below is my code, I have resolved to my Question .Al last i got solution with help of stack overflow team .It is possible to play animation (.gif file) on main thread if you are doing long task in worker thread.And other things is as with official doc QPixmap is does not supporting in worker thread .So i hope guys it will be help for Qt developer.
int worker::do_Work()
{
int i =0;
while (i<1000000)
{
qDebug()<<":count *i=========>"<<i;
i++;
}
qDebug()<<"Worker process finished in Thread "<<thread()->currentThreadId();
emit finished();
}
int mywidget::popup()
{
ui->label_2->setStyleSheet("background-color:rgb(85,255,127);border-radius:10px");
ui->label_2->setWindowFlags(Qt::FramelessWindowHint);
ui->label_2->setText("Please Wait..");
ui->label_2->setAutoFillBackground(true);
QMovie *movie = new QMovie(":images/loader.gif");
ui->label_2->setMovie(movie);
ui->label_2->show();
qDebug()<<"labele show";
movie->start();
myWorker = new worker;
WorkerThread = new QThread;
myWorker->moveToThread(WorkerThread);
connect(WorkerThread, SIGNAL(started()), myWorker, SLOT(do_Work()));
WorkerThread->start();
connect(myWorker, SIGNAL(finished()), ui->label_2, SLOT(close()));
return 0;
}
If the main loop is busy because it is processing events, it will not update the GUI (because the GUI is managed by the main thread).
When you have long processing tasks, execute them in a different thread (or accept to freeze your GUI).
As I said, the GUI is and must be managed in the main 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.
I have an Qt5 c++ app with 2 threads, thread A is started when the main program starts up. The start method of thread A runs successfully.
So far so good. Next, in the main program I send a signal to Thread A to start a QTimer, which it does - but that timer never expires!
Thread B handles tcp connections. When I initiate a telnet connection to my app, thread B fires up and suddenly I see my Qtimer from thread A expiring at normal intervals.
Why is the QTimer from thread A not expiring until thread B starts?
I suspect my threads are getting messed up. note the last section of code below products this:
thread of this: QThread(0x200fe00)
thread of timer: QThread(0x1fff470)
Which suggest my worker object (this), is in a different thread from my timer object. This timer thread address is actually the MAIN thread. Why? I'm confused.
Suggestions?
In my main app I create and start my thread like this:
QThread * MyControllerThread = new QThread(this);
if (MyControllerThread) {
TheController *worker = new TheController(MyControllerThread);
if (worker) {
connect(MyControllerThread, SIGNAL(started()), worker, SLOT(start()));
connect(MyControllerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(MyControllerThread, SIGNAL(finished()), MyControllerThread, SLOT(deleteLater()));
worker->moveToThread(MyControllerThread);
MyControllerThread->start();
}
and in my main app I emit a signal to the new thread:
emit sig_startlocalpeer(Types::EActionLocalServiceStart); // Move the local peer to standby mode to start remote tests
which runs a slot in my thread (TheController object):
connect(&m_remotetestintervaltimer,SIGNAL(timeout()),this,SLOT(expiredRemoteTestIntervalTimer()));
m_remotetestintervaltimer.setTimerType(Qt::VeryCoarseTimer);
m_remotetestintervaltimer.start(REMOTETEST_TIMER_INTERVAL); // Wait between ticks
qDebug() << "thread of this: " << this->thread();
qDebug() << "thread of timer: " << m_remotetestintervaltimer.thread();
Well, it's not a Qt5 bug, it's more an inaccurate understanding of Qt's thread spirit.
In Qt, you have two ways to implement a thread which are using or not an even loop. Here is just a small visual example.
No event loop
myMethodCalledInANewThread
{
do{ ... }while(...);
}
With an event loop
myMethodCalledInANewThread
{
[...]
exec();
}
(Of course you can mix a do/while with an even loop but stay simple).
In QTimer's doc, you can read:
In multithreaded applications, you can use QTimer in any thread that
has an event loop. [...] Qt uses the timer's thread affinity to
determine which thread will emit the timeout() signal. Because of
this, you must start and stop the timer in its thread; it is not
possible to start a timer from another thread.
So I'm pretty sure you don't have a second event loop in your second thread and that's why you have the behaviour you described.
To give you some tips to be totally clear with thread using Qt, I suggest you to read:
QThread doc: https://doc.qt.io/qt-5/qthread.html
QTimer doc: https://doc.qt.io/qt-5/qtimer.html
and a very good article about how QThread implementation is misunderstood by a lot of users:
You're doing it wrong: https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong
I hope it will help ;)
The best answer seems to be a combination of RobbieE and Kuba:
You have to explicitly set the parent of the member variable in constructor. The parent-child feature is a Qt thing that exists among classes derived from QObject, it is not a feature of C++.
I never knew this - I assumed that when an object was created, its members variables automatically had their parent set to the object. Good to know!!
I will keep the code simple so that you guys can see what I'm trying to do ;)
I am aware of all of the locking issues, etc. I'm trying to figure out how signals and slots play with threads.
In main.cpp:
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyConsole c; // Subclasses QThread and implements run()
MyReceiver r(app); // We pass app to MyReceiver for later (see below)
QObject::connect(&c, SIGNAL(sendit()),
&r, SLOT(gotit()));
c.start(); // Start the worker thread
app.exec();
}
Assume that the signals and slots were properly set up in the header files (I've tested and they are). Now, here's the issue:
In MyReceiver.cpp:
void MyReceiver::gotit()
{
QLabel *label = new QLabel(0, "Hello"); // Some GUI element, any will do
app.setMainWidget(*label); // Some GUI action, any will do
}
The question is: Because the MyReceiver object was created in main(), which is on the main thread, does that mean that the slots (e.g., gotit()) will run on the main thread and are therefore safe for doing GUI stuff? Even in cases where the signal was raised from a different QThread (like MyConsole in this example)?
Is there a better way to allow worker threads to interact with the GUI (for example, Obj-C/Cocoa have a "send message on main thread" type of approach). What is "The Qt way" of doing this?
Thanks in advance!
By default (Qt::AutoConnection), slots will run in the thread the QObject was created in. So, no matter from what thread you emit the signal, the slot will be run always in the thread, the QObject "lives" in (if a Qt event loop is running in that thread, otherwise the event can't be delivered). Since the main thread will become the Qt GUI thread, this will work as expected. This is indeed the Qt way of interacting with the GUI.
See also: http://doc.qt.nokia.com/4.7/thread-basics.html (look for thread affinity).
The "Qt way" to emit a signal from one thread and receive it in a different thread is to use a Queued connection
connect( obj, SIGNAL(foo()), other_obj, SLOT(bar()), Qt::QueuedConnection )
From the Qt documentation for Qt::QueuedConnection:
The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.