The last weeks I read a lot about RAII and thought that I should start using smart pointers in my applications. As an example I tried to modify one of my applications. It captures frames from a webcam in a thread, performes image processing in another thread and displays the processed and unprocessed images in QT widgets. One central Object is the CCameraHandler which controls the capturing thread and image processing thread. Up to this point I used 4 plain pointers as members in this class:
CCameraCapture* m_CameraCapture;
CImageProcessor* m_ImageProcessor;
QThread* m_CameraCaptureThread;
QThread* m_ProcessingThread;
In the constructor of CCameraHandler I created the Instances using new and moved the capture object to the thread:
m_CameraCaptureThread= new QThread();
m_CameraCapture= new CCameraCapture();
//Move camera capture object to thread
m_CameraCapture->moveToThread(m_CameraCaptureThread);
That approach worked nicely. Now I wanted to a first test with QScopedPointer and tried to change m_CameraCapture to a QScopedPointer using
QScopedPointer<CCameraCapture> m_CameraCapture;
and initializing it with CameraCapture(new CCameraCapture()) in the initialization list. It compiled nicely and works as it should but when I close the application an the destructors are called I get an error from Qt:"Cannot send events to objects owned by a different thread. Current thread 5ff590. Receiver '' (of type 'CCameraCapture') was created in thread 4b7780" I guess that it has to do with the m_CameraCapture->moveToThread(m_CameraCaptureThread); where I now move a scoped pointer. Is the QScopedPointer automatically parented by CCameraCapture? So far I used
//This connections guarantees that the m_CCameraCapture and m_CameraCapture are deleted after calling QThread::exit()
QObject::connect(m_CameraCaptureThread, SIGNAL(finished()), m_CameraCaptureThread, SLOT(deleteLater()));
QObject::connect(m_CameraCaptureThread, SIGNAL(finished()), m_CameraCapture, SLOT(deleteLater()));
to delete thread an worker when camera capturing is stopped. If m_CameraCapture is now parented by CCameraHandler that might cause the problems. At the moment I am not so sure if it is a good Idea to use a SmartPointer in this case. Any Ideas what might cause this error on destruction?
Edit:
The CCameraHandler dtor looks like this (threads should be deleted before the worker):
CCameraHandler::~CCameraHandler(void)
{
//Stop grabbing and processing
emit stopGrabbing();
emit stopProcessing();
/*Wait for the capture thread to terminate. The destructor of CCamera Handler might be called on application close. Therefore it is important to wait for QThreads to terminate. Else the application might close before threads get deleted*/
m_CameraCaptureThread->exit();
m_CameraCaptureThread->wait();
//Wait for the processing thread to terminate
m_ProcessingThread->exit();
m_CameraCaptureThread->wait();
qDebug() << "CCameraHandler deleted";
}
An object that has been moved to another thread must be destructed either:
From the thread itself, or
From any thread after the thread itself has been destructed.
Caveat: QThread is not safe to be destructed before you stop it. To do that safely to a thread that merely runs an event loop, you should use the following subclass instead:
class Thread : public QThread {
using QThread::run; // final
public:
Thread(QObject * parent = 0) : QThread(parent) {}
~Thread() { quit(); wait(); }
};
Given such a class, destructed from the GUI thread, you simply need to destruct it before you destruct any objects that were moved to the thread. Of course, it's not necessary to hold such objects as pointers at all, but the code below will work whether you hold them directly or as pointers.
class Foo : public Bar {
CCameraCapture m_CameraCapture;
CImageProcessor m_ImageProcessor;
Thread m_CameraCaptureThread;
Thread m_ProcessingThread;
...
}
When the class is destructed, the following happens, in order:
~Foo() body runs (it may be empty).
Members in the ... section, if any, are destructed in reverse order of declaration.
m_ProcessingThread.~Thread runs, followed by superclass destructors (~QThread, and finally ~QObject). Any objects that were moved to that thread are now threadless.
m_CameraCaptureThread.~Thread runs, followed by superclass destructors. Any objects that were moved to that thread are now threadless.
m_ImageProcessor destructors run. As a threadless object, the destruction is safe from any thread.
m_CameraCapture destructors run. As a threadless object, the destruction is safe from any thread.
If you used QScopedPointer<...> to hold those instances, things would be exactly the same, just that every object's destruction would be wrapped in the body of ~QScopedPointer<...>.
Note that the use of even a raw pointer to hold those instances is a premature pessimization: you waste a bit of heap, and access to the instances is a bit slower due to an extra layer of indirection. Those things in isolation may not play a big role, but if there are thousands of objects all coded that way, things can add up.
Don't allocate class members in individual heap blocks unless absolutely necessary.
Problem is that you are doing some UI stuff from none UI thread.
It is hard to tell exactly where is the problem since you didn't give information what exacly CCameraCapture do.
I suspect that after capturing a frame you are setting a pixmap on label (to show frame) instead emit a signal with new frame and connect this signal with respective slot of UI element. So I think that scoped pointer and signal and slots have nothing to do with your problem, problem is that you didn't use signal slot mechanism in place where it was required.
Related
in my application
I've a MainWindow (which is a QtMainWindow class) and a Acquisiton class (which is a QThread class)
Here my very simplified Acquisiton class
//entry point of the thread
void Acquisition::run ()
{
uint8_t* image_addr;
QSharedPointer<uint8_t> image(new uint8_t[IMG_SIZE]);
for (;;)
{
if (isInterruptionRequested())
return;
// here, usb_read() give me the adress of a elem in the ring buffer
img_addr = usb_read(...);
// the ring buffer can possibly be rewritten on the next usb_read() (if bufferlength = 1) so I copy the data into my QSharedPointer
std::memcpy(image.data(), image_addr, sizeof(IMG_SIZE));
// I send this image
emit imageSent(image);
}
}
and in my MainWindow I've
// the slot for the signal imageSent
void newImage(QSharedPointer<uint8_t> image)
{
// process and draw image
}
I don't understand the lifecycle of the QSharedPointer (and std::shared_ptr (imagine the samecode with std::shared_ptr)
Does my QSharedPointer is always valid ?
What append if during processing (MainWindow), the usb_read() occurs and the memcpy write on my image.
In a related question: Waiting slots to be executed before quitting
I see that QSharedPointer keeps my data valid if the acquisition threads stop during data is processing.
In this case, is my signal canceled, my values are copied somewhere or the thread wait for my MainWindow to finish processing ?
Thanks
As it was already written in Resurrection's answer shared pointers are valid as long as they are at least referenced at one location.
In your case you will only have once instance of the shared pointer, which is the one you create at the start of the Acquisition thread. It is referenced in the Acquisition thread as well as in the signal handlers that will be called by QT. As you have only one shared pointer (with one byte array in it) you are now updating the same data buffer on each acquisition and overwrite it, potentially at the same moment when another thread has not yet read it. You can however easily fix that by creating a new shared pointer instance for each sample and pass that one to the other thread in the signal.
The following small change should do it:
//entry point of the thread
void Acquisition::run ()
{
uint8_t* image_addr;
for (;;)
{
if (isInterruptionRequested())
return;
// here, usb_read() give me the adress of a elem in the ring buffer
img_addr = usb_read(...);
// Create a fresh shared pointer in the scope
QSharedPointer<uint8_t> image(new uint8_t[IMG_SIZE]);
// the ring buffer can possibly be rewritten on the next usb_read() (if bufferlength = 1) so I copy the data into my QSharedPointer
std::memcpy(image.data(), image_addr, sizeof(IMG_SIZE));
// I send this image
emit imageSent(image);
}
}
And regarding the cancellation and signaling:
When you call emit signals between different threads in QT then by default a queued connection will be used. This means on the emitting thread the data and the handler that should be called will be put in a queue. The data here is your shared pointer. The queue will held it alive, even if the acquisition thread finishes. Then when the other thread kicks in (MainThread, etc.) the data will be dequeued and the signal handler will be called with it.
Does my QSharedPointer is always valid?
Only after you copy the data to it but after that yes, it will be valid as long as any instance of it exists so as long as your object of type Acquisition exists.
What append if during processing (MainWindow), the usb_read() occurs
and the memcpy write on my image.
Race condition. You would have to use a mutex to lock the resource when processing in the MainWindow. Smart pointers are not inherently thread safe however QSharedPointer uses atomic integer for reference counting so sharing is thread safe. Again, the content is not!
In this case, is my signal canceled, my values are copied somewhere or
the thread wait for my MainWindow to finish processing ?
This depends on how you connect your objects. By default when two QObjects live in two different threads the connection is automatically Qt::QueuedConnection and in that case the arguments are first copied (even if sent as const reference) internally to be posted as event in the receiver's thread. This requires the argument to be copyable and the receiver's thread to be running an event loop. However if you for some reason do Qt::DirectConnection which is default for connection in the same thread it will be equivalent to direct call. This may happen in your case if you have connected the two objects before you moved one of them to a different thread (however maybe Qt does switch all connections to queued ones when QObject::moveToThread is called).
So to answer directly, when queued signal is used the arguments are copied and life time of the caller does no longer matter after the emit.
I have done something like this:
//in the mainwindow's constructor
QThread *thr = new QThread;
soundWorker * work = new soundWorker;
connect(this,SIGNAL(playsound()),work,SLOT(process()));
work->moveToThread(thr);
thr->start();
Shall I delete thr and work at the deconstructor of mainwindow?
You can use the default Qt way of managing memory by assigning a parent to the QThread, i.e. do this:
QThread *thr = new QThread(this);//the mainwindow's is now the thread parent
In Qt, parents are responsible for managing the memory of their children. Thus, the QThread will be automatically deleted when needed.
Then, for your soundWorker, you have a few different solutions. If its lifetime is the same as your mainwindow, as you hint when you ask if you should delete it in the destructor of the mainwindow, you could simply make it a non-pointer member, and its storage duration would then become automatically handled.
The parent thing is specific to Qt though. In general, when you deal with memory yourself, you should resort to wrappers (such as smart pointers) that enables RAII.
Further reading: Qt Trees and ownership model
You can use the QThread::finished() signal in order detect the moment you wish to release the QThread pointer. Same thing could be done with QObject pointers which were moved to the new thread.
Considering that the moment of closing the main window is the moment of closing the whole application and considering that you don't need to further do processing after the application was closed, you can pass the main window pointer as a parent to the QThread by either passing it to the constructor or using QObject::setParent.
Releasing the resources acquired inside the thread handled by QThread must be handled separately as you can't make the QThread object a parent of a resource managed by it - QThread lives in the thread where it was created and not in the thread it manages.
More details here.
The documentation on QObject::moveToThread() for Qt5.3 explains that the moveToThread() method can fail if the object has a parent. How would I detect this failure in my code?
I realize that simply making sure that my object does not have a parent first is probably good enough, but as a defensive programming practice I would like to test the return value from all calls that may fail.
EDIT: I want to stress here after some answers that I am fully aware that I can test if parent is 0 before calling moveToThread. I am looking for possible ways to determine empirically that the moveToThread call actually succeeded.
To reliably get the result of moveToThread(), catch the ThreadChange event of the object undergoing the move (by overriding QObject::event() or installing an event filter), and store whether the event has been seen in a reference to a local variable:
static bool moveObjectToThread(QObject *o, QThread *t) {
class EventFilter : public QObject {
bool &result;
public:
explicit EventFilter(bool &result, QObject *parent = nullptr)
: QObject(parent), result(result) {}
bool eventFilter(QObject *, QEvent *e) override {
if (e->type() == QEvent::ThreadChange)
result = true;
return false;
}
};
bool result = false;
if (o) {
o->installEventFilter(new EventFilter(result, o));
o->moveToThread(t);
}
return result;
}
Long story:
The documentation is wrong. You can move a QObject with a parent to another thread. To do so, you just need to call moveToThread() on the root of the QObject hierarchy you want to move, and all children will be moved, too (this is to ensure that parents and their children are always on the same thread). This is an academic distinction, I know. Just being thorough here.
The moveToThread() call can also fail when the QObject's thread() isn't == QThread::currentThread() (ie. you can only push an object to, but not pull one from another thread).
The last sentence is a lie-to-children. You can pull an object if it has before been dissociated with any thread (by calling moveToThread(nullptr).
When the thread affinity changes, the object is sent a QEvent::ThreadChange event.
Now, your question was how to reliably detect that the move happened. The answer is: it's not easy. The obvious first thing, comparing the QObject::thread() return value after the moveToThread() call to the argument of moveToThread() is not a good idea, since QObject::thread() isn't (documented to be) thread-safe (cf. the implementation).
Why is that a problem?
As soon as moveToThread() returns, the moved-to thread may already have started executing "the object", ie. events for that object. As part of that processing, the object might be deleted. In that case the following call to QObject::thread() on the original thread will dereference deleted data. Or the new thread will hand off the object to yet another thread, in which case the read of the member variable in the call to thread() in the original thread will race against the write to the same member variable within moveToThread() in the new thread.
Bottomline: Accessing a moveToThread()ed object from the original thread is undefined behaviour. Don't do it.
The only way forward is to use the ThreadChange event. That event is sent after all failure cases have been checked, but, crucially, still from the originating thread (cf. the implementation; it would also be just plain wrong to send such an event if no thread change actually happened).
You can check for the event either by subclassing the object you move to and reimplementing QObject::event() or by installing an event filter on the object to move.
The event-filter approach is nicer, of course, since you can use it for any QObject, not just those you can or want to subclass. There's a problem, though: as soon as the event has been sent, event processing switches to the new thread, so the event filter object will be hammered from two threads, which is never a good idea. Simple solution: make the event filter a child of the object to move, then it will be moved along with it. That, on the other hand, gives you the problem how to control the lifetime of the storage so you can get the result even if the moved object is immediately deleted when it reaches the new thread. To make a long story short: the storage needs to be a reference to a variable in the old thread, not a member variable of the object being moved or the event filter. Then all accesses to the storage are from the originating thread, and there are no races.
But, but... isn't that still unsafe? Yes, but only if the object is moved again to another thread. In that case, the event filter will access the storage location from the first moved-to thread, and that will race with the read access from the originating thread. Simple solution: de-install the event filter after it has fired once. That implementation is left as an exercise to the reader :)
QObject::moveToThread fails only if it has a parent. If its parent is NULL then you can move it, else you can't.
EDIT:
What you could do is you can check the object's thread affinity after you called moveToThread by calling QObject::thread and checking if it had really changed its affinity.
QThread *pThread = new QThread;
QObject *pObject = new QObject;
{
QMutexLocker locker(&mutex);
pObject->moveToThread(pThread);
if(pObject->thread() != pThread)
{
qDebug() << "moveToThread failed.";
}
}
Consider that object A is bound to thread T1 and a signal sig1 with an argument of QList < QVariantMap > is fired from thread T2.
The signal is queued on A's event loop, but before handling, A's thread (T1) is quit. The QList< QVariantMap > argument of sig1 is obviously allocated on the stack, I'm guessing that it should clean up itself.
But when? Perhaps when the QThread object itself is destroyed? Does anyone have specific knowledge in this area? In my system, this thread will not simply run once and end at shutdown. It may potentially be started, run for hours, and then quit and be started again later on.
The argument will not be deleted if the thread has been terminated in a correct way like
QThread t;
t.exit();
t.wait();
Now you assert that
The QList< QVariantMap > argument of sig1 is obviously allocated on
the stack
It is not that obvious. Because the receiving thread need to use the data in a deferred execution, emit(myVariantList) will eventually lead to a copy of myVariantList. You don't know where the copy is going to be allocated.
Now to allow posting events with eventual data , ie the classic
Mywidget m;
m.show(); <-- this post at least one event
app.exec();
Those posted events need to be saved just in case of an eventual execution of the event loop. I believe that if the object holding the event loop is not destroyed or the user doesn't explicitly ask for events to be removed, they stay for the lifetime of the QObject.
When a QObject-derived object is being destructed, is it OK to emit a signal from its destructor? I tried it and it seems to work, but I'm not sure if it should be done.
For example, this code
class MyClass : public QObject {
signals:
void mySignal(const QString &str);
public:
QString myString;
~MyClass() { emit mySignal(myString); }
}
would pass a const reference to an object that might be out of scope by the time when the connected slot is executed.
Emission is generally fine (QObject does it too with the "destroyed" signal), including a case as yours. When the connection is direct, the string is still alive. And when it is QueuedConnection, then the string is first copied to the event loop.
If you ask is it OK: Yes, it will not cause any problem in itself.
If you would ask if its a generally safe thing to do in Qt? Definitely not safe. You have to be very mindful what you do if you emit from destructor, and have a good understanding of the Qt event system.
Remember that when a QObject descendant destructs, it disconnects all signals, so the destructed object does not get any more calls on their slots? Well there is a catch: destruction order. The QObject destructor does that disconnect, and it is the LAST to destruct, meaning, in the destruction chain events might still arrive to the "half-dead" object, causing access violations when accessing virtual functions and members of already destructed descendants. The possibility is present if you use the event system, and any of these conditions are met:
In multi threaded environment, if the object is not destructed on its own thread.
In multi threaded environment, if the object's destruction chain triggers the run of a processEvents() on any run path.
In multi threaded environment, if any object on another thread has a direct connection to this object, and it fails to react to its destroyed signal in direct connection.
In single threaded environment, when the destructors sends signals
that might return to the object in a direct connect chain.
I call this effect "life during death", and emiting signals or running any form of processEvents() (typically accidentally) in the destructor increase the chance to create such an error.
Of course, if you can somehow guarantee that not any present or future code will actually trigger any slots during destruction, its perfectly safe to emit from destructor, but its very hard to give such guarantee, and I'd advice simply avoid it whenever possible.