I have a subclass of QObject referred to as myObject, which has a QTimer data member allocated on the heap in the constructor. myObject also has a slot which is connected to the QTimer timeout() signal in the constructor. I refer to the pointer of myObject as myObject_ptr.
I want to run myObject on a different thread from the main thread. Following the relatively new recommendations, I DO NOT subclass QThread. In the main thread, I use myObject as follows:
QThread *thread = new QThread(this);
myObject_ptr->moveToThread(thread);
connect(myObject_ptr, SIGNAL(destroyed(), thread, SLOT(quit())); //thread not needed if no object
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); //to avoid memory leak
connect(thread, SIGNAL(terminated()), thread, SLOT(deleteLater())); //to avoid memory leak
thread->start();
The main thread invokes a function of myObject_ptr which in turn starts the QTimer data member. When it times out, nothing happens, but I expect the slot of myObject to which the timer's timeout() signal is connected to be invoked. What is the problem? How do you make this work. It works flawlessly if myObject is run on the same thread where it was created i.e. main thread.
From all the readings I've done, I think the new thread I am creating might not be processing events because it doesn't have it's own event loop. I also read documentation/articles contrary to that, saying that when the thread starts, the run() function calls exec() and you have an event loop.
Could someone help me please?
I could probably get it to work correctly if I subclass QThread, but based on current recommendations, I would prefer to avoid doing that.
Thank you in advance.
I solved my problem!! In the constructor of MyObject, the timer is allocated on the heap as follows:
timer_ptr = new QTimer(this);
but to work correctly, it should be:
timer_ptr = new QTimer(0);
and in the destructor, delete the object manually:
timer_ptr->deleteLater();
I guess when they say can't move an object with a parent to a thread, they really do mean ALL objects, including data members of the object actually being moved to the new thread.
Happy coding.
Related
My code is as follows:
void DrpltGyslPanel::paint(QPainter *painter)
{
view_->render(painter, boundingRect(), view_->viewport()->rect(), Qt::KeepAspectRatio);
}
DrpltGyslPanel is subclass of QQuickPaintedItem, view_ is instance of QGraphicsView .And I know DrpltGyslPanel::paint is called in QSGRenderThread, but what is this Timer used for?
And this also caused child threads endless loop.
How can I kill timer exactly? Or one more step for what exactly caused child threads endless loop?
--------------------------------added at 2019/12/19
If the QGraphicsView shows, endless loop won't appear in the Release build and will in the Debug build.
Probably, calling render will internally stop a timer which lives in another thread.
You cannot paint on QPainter which lives in another thread.
You can ask the _view to render itself into a QImage and send it back to DrpltGyslPanel using another signal.
You can also have a QImage instance in DrpltGyslPanel, share it with _view and use QMutex to block those threads from reading or writing the QImage.
QGraphicsView::addItem will start a timer by default interval(2000ms) at here.QGraphicsView::render will kill timer at here.When killing timer will estimate whether the current thread is thread timer lives to make sure timer usage is in the same thread.So we can not invoke QGraphicsView::render in DrpltGyslPanel::paint from QSGRenderThread.
The code is corrected as follows:
void DrpltGyslPanel::update(const QRect &rect)
{
renderPixman = QPixmap(view_->viewport()->rect().size());//renderPixman is member variable
QPainter painter(&renderPixman);
view_->render(&painter, boundingRect(), view_->viewport()->rect(),
Qt::KeepAspectRatio);
QQuickPaintedItem::update(rect);
}
And why which will caused child threads endless loop, that is timerEvent alaways triggered.
I want to terminate (finish) a QThread, when my app will be destroyed.
So I invoke terminate() and quit() within a destructor of my derived class from `QThread.
Is it safe?
class Session : public QThread
{
Q_OBJECT
private:
CheckerAdapter *inst;
public:
explicit Session(CheckerAdapter *inst, QObject *parent = 0);
void run();
~Session(){
terminate();
quit();
}
};
Using QThread::terminate() can lead to memory corruption, since the thread is just terminated without its knowledge, it can be doing anything while it gets terminated:
Warning: This function is dangerous and its use is discouraged. The thread can be terminated at any point in its code path. Threads can be terminated while modifying data. There is no chance for the thread to clean up after itself, unlock any held mutexes, etc. In short, use this function only if absolutely necessary.
To safely terminate a QThread, You need to have a way to tell the thread that it has to terminate, and when the thread gets that, it should return from its run() implementation as soon as possible. Qt provides two ways to do this:
If your thread runs an event loop (i.e. You don't override run(), Or if you call exec() in your custom run() implementation), You can call QThread::quit()/QThread::exit() from any thread. This will cause the thread event's loop to return as soon as it finishes processing current events. There is no data corruption, as current processing doesn't get terminated.
If your thread does not run an event loop, You can use QThread::requestInterruption() from any other thread to tell the thread that it should stop. But you have to handle that in your implementation of run() using isInterruptionRequested()(otherwise, calling requestInterruption() will do nothing).
Note:
If you are using any of the above methods to stop your QThread in its destructor, You have to make sure that the thread is no longer running after the QThread object gets destructed, You can do that by calling QThread::wait() after using quit()/requestInterruption().
Have a look at this answer for a similar implementation of a QThread subclass.
I have a class, audio_engine_interface, and in main.cpp, I add it to the QML thing.
viewer.rootContext()->setContextProperty("engine", engine);
In audio_engine_interface, I have a audio_engine class, which is computationally intensive—it needs to run on its own thread.
void audio_engine_interface::play()
{
QThread thread;
thread.start();
engine->moveToThread(&thread);
engine->play(); // Will use 100% of CPU
}
However, when I do this, the whole QML thread locks up, meaning I can't pause (pretty important). Am I missing something?
EDIT:
This thread won't mess up anything or access objects from other places. However, it does have a pause function that will need to be called at some point. For what it's worth, the engine is doing pitch shifting.
This is a problem: -
Qthread thread;
Creating a QThread object like this is creating it on the stack. When the function ends, the object will go out of scope and delete the QThread object.
You need to dynamically allocate the object on the heap: -
QThread* thread = new QThread;
Then remember to delete the thread, or set it to delete itself: -
//Qt 5 connect syntax
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
You should also be aware of thread affinity (the thread which an object is running on). I suggest reading this article on how to use QThread properly.
You have so many problems.
when you move to thread your object must not have a parent
your thread object is local variable so it will day immediately when udio_engine_interface::play() end execution
you are invoking you engine->play(); method directly and this means that it will be executed in current thread.
moveToThread means that slots invked by signals connected using default 5th parameter (Qt::AutoConnection) will be queued in event loop of given thread.
The easiest way to fix it is use QtConcurrent:
void audio_engine_interface::play()
{
QtConcurrent::run(engine, &EngineClass::play);
}
Depending what your engine does you should make it thread safe (use mutex locks an so on), without details it is hard to tell, what exactly you should do.
I wanted to create QObject (object) with the child QThread (thread) with that object as parent (for keeping thread alive while object is alive) and make object.moveToThread(thread) but signal to start the thread isn't working in this case.
Simply:
object owns thread
object moves to thread
signal starting thread isn't working
What's going on?
[Edit]: Throwing away my initial answer due to the comments
Maybe do it like the following:
Create the Object
Create the Thread, but don't assign a parent to it
Connect the Thread's finished() signal to its deleteLater() slot as usual
Connect the Object's deleted() signal to the thread's stop() slot
Then, when you delete the Object, it will emit deleted() which will stop the thread. The thread will emit finished() which will call its deleteLater() slot.
I'm working with QThread and slots/signals mechanism; I know there's a lot of threads about this on the Web in general and here at SO in particular, but I still could not find a solution. Anyway, here is the context.
The piece of code I am trying to come up with is aimed at controlling though the GUI an eventually long process, hence the use of a QThread.
I have a window with two buttons, start and stop. My Window also has a QThread and Task, where the latter inherits from a QObject. I do want to be able to stop my task while it is running, and to prevent starting it again if start is clicked while it is already running.
Here is an excerpt of Task (which fakes the long process):
class Task: public QObject
{
public:
Task(): QObject(), stop_(true) {}
private slots:
void startTask()
{
stop_ = false;
run();
}
void stopTask()
{
stop_ = true;
}
void run() const
{
while ( ! stop_)
{
sleep(1);
}
}
bool stop_;
};
I made two connections between the buttons and the task in the constructor of my Window:
class Window: public QWidget
{
public:
Window()
{
// Instantiate buttons and put them in a layout.
// ...
connect(buttonStart_, SIGNAL(clicked()), &task_, SLOT(startTask()));
connect(buttonStop_, SIGNAL(clicked()), &task_, SLOT(stopTask()),
Qt::DirectConnection);
task_.moveToThread(&thread);
thread_.start();
}
private:
QPushButton buttonStart_;
QPushButton buttonStop_;
QThread thread_;
Task task_;
};
I used Qt::DirectConnection in the second connect() in order to "force" processing of my signal requesting to stop the task, as (as I understand) task_ needs to return from its work before processing events further (if I use the default connection, all my clicks are processed after my task is "done").
Here, the Qt::DirectConnection "bypasses" the event queue, and that way I can stop my task. But to be honest I don't know if that is the proper way to do it, or if it is a workaround (thus possibly the root of my problem).
Anyway, this works OK that way, but when I start playing with my buttons, the GUI gets eventually frozen, and that's my problem!
Any help is welcome; thanks for your time!
Using a DirectConnection means that the slots will be executed in the UI thread (while your task thread is still running). This is not what you want. The way to handle this is to use an event loop in your thread, by running with QThread::exec().
In order for your thread to be able to respond as you want, you will need to ensure that the thread is able to process incoming events. There are a few ways to deal with this. One would be to call QCoreApplication::processEvents() occasionally while your task is running. Another is to use a QTimer connected to a slot which performs some processing. The important thing is to make sure that the event loop in your thread can run.
The first thing you need to understand is which thread your signal/slot connections are being executed in.
The default behavior in this particular case is to use a Qt::QueuedConnection, which will put your signal event onto the receiving thread's event queue. In the case of a Qt::DirectConnection, the slot is executed in the thread of the object that emitted the signal.
Using a Qt::DirectConnection would only be safe in this instance if you put a mutex around your stop_ variable to prevent both threads from accessing it at the same time.