[SOLVED] QMetaObject::invokeMethod thread safety
-
Hi
A pointer is defined in the Main Thread as a member of QThread subclass. This means the pointer value (not the object) lives in the Main Thread. Is it safe to use this pointer as the first parameter in QMetaObject::invokeMethod when communicating between threads? I'm not sure if the first parameter in QMetaObject::invokeMethod needs to be based on QSharedPointer or normal pointer is safe as well. BTW, I'm trying to avoid usage of MoveToThread().
Sample code:
@
Class MyObject:public QObject ...class ThreadA: public QThread
{
Q_OBJECT
public:
run () {
MyObject InstanceMyObject;
m_MyObject = &InstanceMyObject;
}
MyObject * m_MyObject;
};// Inside Main Thread
QPointer<MyThread> globalMyThread = new MyThread();
MyThread-start();// Inside Thread B
QMetaObject::invokeMethod(globalMyThread->m_MyObject,"MySlot",Qt::QueuedConnection );
@Thanks!
-
I assume that MyThread is ThreadA in #15 and MyThread is globalMyThread in #16.
There is no smart pointer requirement on the part of Qt, but they should be used to ease your life. Unfortunately your piece of code does not allow for drawing any conclusion whether you should use or have to use smart pointers as it does not provide any information about the projected lifetime of the various objects.
What I can tell you is that storing pointers to stack objects is almost always a horrible idea, especially if they span across multiple threads, and using smart pointers, which try to delete those objects, is even worse.
In additon, subclassing QThread is no longer the recommended way of using QThread. Take a look at "Thread, Events and QObjects":http://qt-project.org/wiki/ThreadsEventsQObjects and "You are doing it wrong":http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/.
Why do you want to avoid moveToThread()? It is usually vital for multithreaded programming.
-
Thanks for the replies.
I store pointer to stack object only for use in first parameter in QMetaObject::invokeMethod. In my code InvokeMethod cannot happen if the destination object doesn't exists. I prefer creating objects on the stack inside QThread::run to ensure better memory management in case of a very long code. I didn't want to put any additional members in QThread subclass but I need to have public access to the object created in the thread so I can invoke it from another thread. I have a Thread container class that starts one thread when the previous one in the seria started so MoveToThread doesn't really fits there, there should be a way to go without it.
Let me try to explain again:
@Thread_A:run()
{
MyObject_A instanceMyObject_A;
}Thread_B:run()
{
MyObject_B instanceMyObject_B;
}Thread_C:run()
{
MyObject_C instanceMyObject_C;
}MyObject_B::MyObject_B():QObject(0)
{
// I want to use pointer here to an object created in another thread.
// The pointer variable "PointerTo_instanceMyObject_A" below (not the object)
// can possibly be accessed from multiple threads, is that thread safe?
// I check the source for invokeMethod and couldn't see any access protection.
QMetaObject::invokeMethod(PointerTo_instanceMyObject_A,"MySlot",Qt::QueuedConnection );
}MyObject_C::MyObject_C():QObject(0)
{
QMetaObject::invokeMethod(PointerTo_instanceMyObject_A,"MySlot",Qt::QueuedConnection );
}@ -
As long as you just dereference the pointer and you can absolutely make sure that it isn't dereferenced before the object is created and after it has been deleted there is no need for any protection mechanism.
You must not use a smart pointer in this case as you will end up <code>delete</code>'ing a stack variable. There is no need to use stack objects for lifetime management - that's what smart pointers are for. You will have to allocate objects on the heap for use with smart pointers. Use QScopedPointer to tie the lifetime of objects to scopes and use QSharedPointer if you additionally need reference counting.
Be aware that for having queued signals working you will need an event loop in the receiving thread, which is not the case in your example.
Have you read the articles I've linked?
-
[quote author="Lukas Geyer" date="1332150884"]You must not use a smart pointer in this case as you will end up <code>delete</code>'ing a stack variable. There is no need to use stack objects for lifetime management - that's what smart pointers are for. You will have to allocate objects on the heap for use with smart pointers. Use QScopedPointer to tie the lifetime of objects to scopes and use QSharedPointer if you additionally need reference counting.
[/quote]I can use QScopedPointer/QSharedPointer inside <code>QThread:run</code> for better memory management, but I will still need to access this pointer from another thread inside the <code>QMetaObject::invokeMethod</code>. I can define QScopedPointer/QSharedPointer as a global pointer but I want to destroy the objects created in the thread when <code>QThread:run</code> returns not when application quits. In a case I use a global pointer (smart or normal) inside InvokeMethod in various threads, does the access to the pointer variable (that holds the value - memory address of the pointed object) is thread safe? What if this global pointer is used in InvokeMethod in multiple threads at the same time?
[quote author="Lukas Geyer" date="1332150884"]Be aware that for having queued signals working you will need an event loop in the receiving thread, which is not the case in your example.
[/quote]Yes I have event loop in my real code provided by <code>exec()</code>, sorry I just wanted to show the important parts only. -
[quote author="Marcus Frenkel" date="1332153361"]In a case I use a global pointer (smart or normal) inside InvokeMethod in various threads, does the access to the pointer variable (that holds the value - memory address of the pointed object) is thread safe? What if this global pointer is used in InvokeMethod in multiple threads at the same time?[/quote]
It is absolutely valid that multiple threads access the same pointer at the same time for reading.You are in trouble if at least one thread writes to a shared memory location, in which case you will have to serialize access (using locks or mutexes).
-
[quote author="Lukas Geyer" date="1332156728"]It is absolutely valid that multiple threads access the same pointer at the same time for reading.
You are in trouble if at least one thread writes to a shared memory location, in which case you will have to serialize access (using locks or mutexes).[/quote]
It's clear now, thanks a lot!